Giter VIP home page Giter VIP logo

lighthouse's People

Contributors

4levels avatar alberthaff avatar cappuc avatar chrissm79 avatar dependabot[bot] avatar enzonotario avatar eriktisme avatar georgeboot avatar hailwood avatar hosmelq avatar jasontheadams avatar k0ka avatar liepaja avatar lorado avatar lucasmichot avatar megawubs avatar mostafa-rz avatar olivernybroe avatar omacranger avatar oozman avatar pyrou avatar robsontenorio avatar spawnia avatar stayallive avatar stevemoretz avatar thekonz avatar tlaverdure avatar wimwidgets avatar yaquawa avatar zn4rk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lighthouse's Issues

v2-Beta test progress

Love it!, so simple!

Got to the point where I'm getting the schema generated into a React-Native project using Relay Modern, retrieving the schema form the server with the graphql get-schema -I introspection method, hardest part was figure out the mutation. (working example bellow)

Need a bit of advise how you handle or its up to us the auth, resolve, middleware, thing. Like for example: @inject(context: "auth.id"))
Add the route point to the crsss thing exclude? I mean, to resolve the context, maybe using passport, if you can share your approach I'm sure it will be very inspirational. ๐Ÿค” [@]middleware() directive probably?

For a custom Directive, like example bellow, Is it class name or the name attributed whats important?

<?php

namespace App\GraphQL\Directives;

use GraphQL\Type\Definition\ResolveInfo;
use Nuwave\Lighthouse\Schema\Values\FieldValue;
use Nuwave\Lighthouse\Support\Contracts\FieldResolver;
use Nuwave\Lighthouse\Support\Traits\HandlesDirectives;

class Context implements FieldResolver
{
    use HandlesDirectives;

    /**
     * Name of the directive.
     *
     * @return string
     */
    public function name()
    {
        return 'context';
    }

    /**
     * Resolve the field directive.
     *
     * @param FieldValue $value
     *
     * @return FieldValue
     */
    public function handle(FieldValue $value)
    {
        return auth()->id();
    }
}

routes/schema.graphql

type User @model {
  id: ID
  name: String!
  email: String!
  created_at: String!
  updated_at: String!

  avisos: [Aviso!]! @hasMany
}

type Aviso @model {
  id: ID
  uuid: String!
  name: String!
  user: User!
}

type Query {
  viewer: User @auth
}

type Mutation {
  createUser(
    name: String!
    email: String! @validate(rules: ["email", "unique:users,email"])
  ): User @create(model: "App\\Models\\User")

  createAviso(name: String, user_id: Int @inject(context: "auth.id")): Aviso
    @create(model: "App\\Models\\Aviso")
}

This is how I'm doing the middleware,

    'directives' => [__DIR__.'/../app/GraphQL/Directives'],

    'route' => [
        'prefix' => 'kapi',
        // 'middleware' => ['loghttp']
    ],
    /*
    |--------------------------------------------------------------------------
    | Namespace registry
    |--------------------------------------------------------------------------
    |
    | This package provides a set of commands to make it easy for you to
    | create new parts in your GraphQL schema. Change these values to
    | match the namespaces you'd like each piece to be created in.
    |
    */
    'namespaces' => [
        'models' => 'App\Models',
        'mutations' => 'App\GraphQL\Mutations',
        'queries' => 'App\GraphQL\Queries',
        'types' => 'App\GraphQL\Types',
        'fields' => 'App\GraphQL\Fields',
        'scalars' => 'App\GraphQL\Scalars',
        'connections' => 'App\GraphQL\Connections',
        'dataloaders' => 'App\\GraphQL\\DataLoaders',
    ],

best solution so far for Laravel from a personal perspective.

Happy coding!

Lighthouse v2 Roadmap

Overview

I'll fill this section out when time permits but I'm currently working on v2.0 of Lighthouse. Spoiler alert, it's a large breaking change that (at the moment) doesn't have an upgrade path. That being said, with the new approach (schema first), the benefits that come with these breaking changes along w/ how much more the end-user can do with it (i.e., plugins) make this a requirement. I want Lighthouse to be approachable to anyone, doesn't require anything but a schema to get started, and provides the user w/ enough flexibility to extend Lighthouse to fit just about any project regardless of complexity.

screen shot 2018-03-04 at 5 22 39 pm

By defining the schema above, Lighthouse can:

  • Create and register User and Task types
  • Auto resolves the User hasMany task relationship
  • Auto resolves the Task belongsTo User relationship
  • Create a me query that requires and returns the authenticated user
  • Generates a createUser mutation that will autofill and create a new User w/ rule validation on the email argument
  • Generates a createTask mutation that will inject the authenticated user's id into the user_id argument (currently trying to figure out how to remove this argument from the schema the client sees). Mutation requires that the user can create tasks via a policy

That's a lot it can do for you w/ only 31 lines and no code!!!

Road to 2.0

  • Directive system that the user can extend to resolve Nodes/Fields/Args
  • Context argument injector
  • create/update/delete autofill directives
  • Query/Mutation middleware
  • Ability to add scopes to filter relationships
  • Use graphql-php built in Deferred class to handle relationships and prevent N+1
  • Cache schema AST
  • Ability to attach single directive to Argument/Field/Node
  • Create Walkthrough video
  • Update Documentation

For those who want to check out the example project that the Walkthrough will be based off of, here it is! I'm going to try and work in as many built-in directives as possible to highlight what Lighthouse can do "out of the box" as I prep for the v2.0 release.

After 2.0

  • Stubs for GraphQL types
  • Auto create/update/delete mutation generation for models (boolean in @model directive)
  • Custom Context - Allow creation of custom context when request comes in
  • Subscriptions (I had this working but there we some great updates made to Ratchet that I will need to investigate)

[Docs] How would I...

This issue exists as a bit of a dumping ground of "How would I do this" questions that we could potentially answer and add to the docs in a specific section.

As any answers are posted the original asker should add them to their question to keep things easy to read. I've provided a few below to give us some structure.

Error running graphql endpoint

Okay first off im running a windows machine. I installed this library for graphiql-ui https://github.com/noh4ck/laravel-graphiql however when i got to the route localhost/graphiql-ui i get an error in the window where the queries should run. Am i doing something wrong? How would i configure lighthouse to work with that library?
Here is the error
image

Lumen support

This is exactly the kind of library that should be used on a small framework. All you really need is some routing and GraphQL magic.

With that said, is there any particular reason you are using Laravel only features like the router?

Document alternate syntax if `schema()` function unavailable.

If something has already registered a function called schema() ours won't be registered so we need to know the alternative syntax.

GraphQL::schema()->group(['namespace' => 'App\\Http\\GraphQL', 'middleware' => ['auth']], function () {
    GraphQL::schema()->group(['namespace' => 'Types'], function () {
        GraphQL::schema()->type('user', 'UserType');
        GraphQL::schema()->type('viewer', 'ViewerType');
        GraphQL::schema()->type('task', 'TaskType');
    });

    GraphQL::schema()->group(['namespace' => 'Queries'], function () {
        GraphQL::schema()->query('viewer', 'ViewerQuery');
    });

    GraphQL::schema()->group(['namespace' => 'Mutations'], function () {
        GraphQL::schema()->mutation('createUser', 'CreateUserMutation');
    });
});

Possibly also need something in there about this format instead of the namespaces as well since IDEs can understand what we're on about in this form

GraphQL::schema()->group(['middleware' => ['auth']], function () {
    //Types
    GraphQL::schema()->type('user', \App\GraphQL\Types\UserType::class);
    GraphQL::schema()->type('viewer', \App\GraphQL\Types\ViewerType::class);
    GraphQL::schema()->type('task', \App\GraphQL\Types\TaskType::class);

    //Queries
    GraphQL::schema()->query('viewer', \App\GraphQL\Queries\ViewerQuery::class);

    //Mutations
    GraphQL::schema()->mutation('createUser', \App\GraphQL\Mutations\CreateUserMutation::class);
});

Or if you prefer the short syntax this works too

use App\GraphQL\Mutations\CreateUserMutation;
use App\GraphQL\Queries\ViewerQuery;
use App\GraphQL\Types\TaskType;
use App\GraphQL\Types\UserType;
use App\GraphQL\Types\ViewerType;

GraphQL::schema()->group(['middleware' => ['auth']], function () {
    //Types
    GraphQL::schema()->type('user', UserType::class);
    GraphQL::schema()->type('viewer', ViewerType::class);
    GraphQL::schema()->type('task', TaskType::class);

    //Queries
    GraphQL::schema()->query('viewer', ViewerQuery::class);

    //Mutations
    GraphQL::schema()->mutation('createUser', CreateUserMutation::class);
});

PageInfo returns incorrect cursor

Hey everyone,

I was implementing relay modern paginated container when I came across and pagination bug or a misconfiguration from my side.

fragment Tournaments_diceviewer on Dice { competitions(after: null, orderby: "id", hasLeagueTableOnly: true) { pageInfo { count total currentPage hasNextPage endCursor hasPreviousPage startCursor } edges { cursor node { id name short_name full_name image order __typename } } } }
The above fragment queries the connections and returns the first 15 nodes with now problem.
The endCursor returned in the first 2 pages is correct. Then on page 3, the endCursor returned is for the last record in the collection.

I had a look at the PageInfoType definition and came across this:

'endCursor' => [ 'type' => Type::string(), 'description' => 'When paginating forwards, the cursor to continue.', 'resolve' => function ($collection) { if ($collection instanceof LengthAwarePaginator) { return $this->encodeGlobalId( 'arrayconnection', $collection->lastItem() * $collection->currentPage() ); } }, ],
I don't understand line 71 or $collection->lastItem() * $collection->currentPage()

What I did was I removed the "* $collection->currentPage()" and everything works great

As for my connection definition:

public function resolve($parent, array $args, $context, ResolveInfo $info) { return $parent->competitions()->getConnection($args); }
competitions() returns a simple eloquent hasMany

Please advise
Thanks

Read `name` from object in schema

On our objects (Types/Mutations/Queries) we have a name key in the $attributes.

I'm proposing that if we call GraphQL::schema()->type($namespace) (or any of the other related functions) then we instantiate an instance of the passed class name and use $instance->name as the name.

Likewise with my open pull request it would be e.g.

GraphQL::schema()->types([
    \App\GraphQL\Types\UserType::class,
    \App\GraphQL\Types\ViewerType::class,
    \App\GraphQL\Types\TaskType::class
]);

I've opened this as an issue rather than a pull request as I have not yet delved too deep into how your group() function works and what may need to be changed to make it work with that if anything.

Thoughts?

Is there a way to get the schema.json output like lighthouse v1 had?

So first off lighthouse v2 is awesome!!!! great work! It's so much more simple than v1. I'm currently working on upgrading a project to using lighthouse v2 and I'm getting stuck updating to Relay Modern, because it requires either the schema.graphql or schema.json file to compile the static files from, but it does not recognize the fields when you do things like this someFeild: [Type!]! @paginate(type:"relay" model: "SomeModel") because it does not know that translates to someFeild(first: Int! after: String):

So am I missing something obvious? Or is this something that's not currently supported?

Contributing

Hi!

Great work on Lighthouse so far! I've found a few things that I would like to submit PR's for.

I tried to clone the repository and running composer install to get setup but got greeted with a bunch of errors (Wrong phpunit version, ModelFactory not working, redeclaring of classes).
I'm probably doing something wrong.

Do I need a Laravel installation to contribute? Or should the tests work without it?

Thank you!

Remove Fluent

This is an opinionated issue, but I would like to test the waters.

I really like the Service Container and the dependency injection Laravel offers. Lighthouse currently resolves classes that inherits from either GraphQLField and GraphQLType via the service container, but both of these classes extends Illuminate\Support\Fluent, which in turn takes the argument $attributes in the constructor.

I've gone through the code, and can't really see why we are extending Fluent in the above mentioned classes. There's a few others that need it, but not those two specifically. If we remove the parent, we don't have to call the parent constructor if we need to use the dependency injection (we don't actually have to call the parent-constructor as it is right now, but my code inspector complains if I leave it out).

class GameType {
    protected $gameRepository;

    public function __construct(GameRepositoryInterface $gameRepository) {
        $this->gameRepository = $gameRepository;
    }
    ...

Instead of

class GameType {
    protected $gameRepository;

    public function __construct(GameRepositoryInterface $gameRepository) {
        parent::__construct();
        $this->gameRepository = $gameRepository;
    }
    ...

Thoughts? I'd be happy to provide a PR doing this.

[Lumen] Working with relations - Call to undefined function Nuwave\Lighthouse\resolve()

Hi all,

I'm trying to get relations working following the video tutorial (and any other info I can find), but I keep getting the following error: Call to undefined function Nuwave\Lighthouse\resolve()

I have the following configuration in place (simple Room -> Comments relation):
App\GraphQL\Schemas\pms.graphql

type Room {
  id: ID! @globalId
  name: String
  available: String
  reference: String
  details: String
  location: String
  comments: [Comment!]! @hasMany
}
type Comment {
  id: ID! @globalId
  reference: String
  title: String
  content: String
  created_at: DateTime
  room: Room! @belongsTo
}

App\GraphQL\Queries\Rooms.php

<?php

namespace App\GraphQL\Queries;

use Nuwave\Lighthouse\Support\Schema\GraphQLResolver;
use Illuminate\Auth\Access\AuthorizationException;
use App\Models\Room\Room;

class Rooms extends GraphQLResolver
{

    public function resolve()
    {
        if(!$this->context || !$this->context->user){
            throw new AuthorizationException('Unauthorized');
            return null;
        }

        // query
        $roomsQuery = Room::query();

        return $roomsQuery
            ->where('reference', 'NOT LIKE', '%9999')
            ->orderBy('lft')
            ->get()
            ;
    }
}

App\GraphQL\schema.graphql

#import ./Schemas/pms.graphql

scalar DateTime @scalar(class: "DateTime")

type ResponsesPayload {
  success: Boolean!
  msg: String
  payload: String
}

type Query @group(middleware: ["auth:api", "scopes:graphql"]) {
  rooms: [Room!]!
}

As soon as I try the following query, I get the forementioned error

query getRooms {
  rooms {
    id
    name
    available
    comments {
      reference
      title
      content
    }
  }
}

I'm probably overlooking something obvious here..
I still have some other questions related to this:

  • how do I declare a different model name in the .graphql type definition? (eg. I have a App\Model\Room\Comment and a App\Model\Booking\Comment model) -> can I add eg type Comment @model(model: "App\\Models\\Room\\Comment") { ... }
  • how should I go about structuring the various graphql files? I can't seem to define multiple Query entries when I try to separate them into different files
  • how can I learn the ins and outs about the various schema elements? I went through the various test files to look for examples but I couldn't find eg. the uses of the @model directive
  • when creating Query classes, should I extend GraphQLResolver or GraphQLQuery

Thanks again for this great library, I hope I can get rolling with it very soon!

Kind regards,

Erik

Edge command runs out of memory

Thank you for the amazing package :)

I have an issue with the edge command, not sure if its related to my env.

php artisan lighthouse:edge Competition

The command runs out of memory (1024 MB)

PHP Fatal error: Allowed memory size of 1073741824 bytes exhausted (tried to allocate 45056 bytes) in /Users/sherief/Development/git/dice/backend/vendor/laravel/framework/src/Illuminate/Console/GeneratorCommand.php on line 92
PHP Fatal error: Allowed memory size of 1073741824 bytes exhausted (tried to allocate 32768 bytes) in /Users/sherief/Development/git/dice/backend/vendor/symfony/debug/Exception/FatalErrorException.php on line 1

Any one facing the same issue?

Thanks

[Feat] Argument filters

I can't figure out how we can set a field to be filterable.
For example i have some users and I would like to make the name something i can filter by.

Relay Modern

Hey guys, I love that lucasmichot and chris are doing so much work on the package right now.
Thanks guys.

Since Relay Modern is coming out soon, I wanted to ask if you plan on making it work with it or if it maybe works with it already?

I am going to start a new project and I'm not sure if I should start it with laravel because I would love to start with Relay modern right away.
What do you guys think about the roadmap for the next couple of months?

[BUG] Relay connection offset error

Hi there,

Anyone using with relay connection?
Just discovered that I got a jump from offset 10, to offset 40, having the pagination on $first:10.

its so rare...

This isn't the worst, what I'm getting more confuse its with the fact that to be able to query relay connections I must change type to connection, if I change it to type:"relay" I must use count instead of first whats not the natural way to query relay connections.

Have downloaded the https://github.com/nuwave/lighthouse-example and seems to get same behaviour.

composer its using version 2.0.3, have even cleared composer cache, fresh install of packages, and not going forward.

@chrissm79 I need your help on this: have done following:

jobs: [Job!]! @paginate(type: "connection", model: "App\\Job")
jobs: [Job!]! @paginate(type: "relay", model: "App\\Job")

query QueryJobs{
  jobs(first:3){
    edges{
      node{
      title
      }
    }
  }
}

Please clean up the branches :)

Hey @chrissm79 ,

Any chance you could delete the old branches for V1, and add a quick note to the readme regarding the other branches.

E.g. what's the difference between

master
v2-beta
v2.0.x

Cheers!

Add Query as a Query

So this is not really an issue, but I think it's worth discussing and I want it documented so that other people might find a use for it.

The background to this discussion is this issue. The current version of Relay (0.10) doesn't support root fields/queries to be arrays. In the linked issue above they suggest a workaround until Relay 2 is released. An updated version of the workaround has been suggested in this issue: lucasbento/graphql-pokemon#1

I don't think we should build support for this, since Relay 2 is coming, but the easiest way to add this to a project would be to extend GraphQL - since it's registered through Laravel's service container, and override the buildSchema()-method:

Nuwave\Lighthouse\GraphQL

public function buildSchema() { 

	...
	
	$fields = $queryType->config['fields'];
	$fields['query'] = [
	    'args' => [],
	    'type' => $queryType,
	    'resolve' => function() {
	        return true; // we need to have a closure that returns something
	    }
	];
	$queryType->config['fields'] = $fields;
	
	...
	
	return new Schema([
	            'query' => $queryType,
	            'mutation' => $mutationType,
	            'types' => $this->typesWithInterfaces->all(),
	        ]);

This is a hack(!) and probably shouldn't be used in production.

One could get away with doing something similar in their extension if they first call the parent on the overridden method (buildSchema()) and then get the mutations, queries and types from the generated Schema, and then instantiate a new Schema.

This is not recommended, since this package will most likely change.

If anyone has any suggestions on how (and why) support for this should be implemented for real, please, leave a comment!

New GraphQL implementation

Hello Maintainers,

We have been working on a new PHP implementation of the GraphQL specification and we are closing in on a version 1.0 release. I just wanted to stop by and mention this to see if you're interested in teaming up with us. There is a Slack for the project where we can invite you.

The repository can be found here:
https://github.com/digiaonline/graphql-php

Best,
Christoffer

How to query top level collections?

Hey @chrissm79,

Any chance you could provide an example of how to query top level collections?

I.e. We've got examples in the docs of how to get all jobs a user is connected to, but how can we write a query that returns a collection that is not a connection

e.g. assuming we have a user type defined simply returning all users in the system, or we have a job type and returning all jobs in the system that have their status set to "open".

Cheers,

Handling file uploads

Hey @chrissm79,

I'm curious about your thoughts on file uploads?

Right now I'm quite happy handling the uploads through a separate controller that simply accepts the file, marks it as transient and returns an ID.

Then for a mutation we simply send across a list of these transient file ids, and the mutation connects the file to the resource and marks it as a completed file, any files that are not marked as completed get deleted after 30 minutes.

For me this has the advantage of being able to use pretty much any standard file uploader on the frontend.

But I know there are some who like to keep everything within graphql, there's been some discussion going on at folkloreinc/laravel-graphql#125 regarding this.

What are your thoughts here?

Versions 2.0.X not up to date with master

@chrissm79 , seems that if you just use the composer require nuwave/lighthouse the versions there are not properly up to date with master branch.

by default you will get today the 2.0.3 and this version as you can see comes with this fix we had several commits ago.

screen shot 2018-04-27 at 02 05 43

See picture? should be 'relay' instead of 'connection', and this is whats causing this strange behaviour on production builds.

A workaround will be to use the composer require nuwave/lighthouse:dev-master or master branch for now, I was wondering how you was doing the releases when no merges are carried, as you see in sourcetree graphical the branch never get merged.

I didn't notice till today because I was using dev-master.

Hope it helps-

screen shot 2018-04-27 at 02 13 00

Soft deleted models arg directive

Was thinking if we should add a directive for soft deleted models?

So we have an arg directive called @trashes or @softdeletes or something better than that, this arg directive would work in the following way.

type Query{
    companies(trashed: Trash @trashes): [Company!]! @paginate(model: "Company", type: "relay")
}

enum Trash {
  ONLY @enum(value: "only")
  WITH @enum(value: "with")
  WITHOUT @enum(value: "without")
}

{
  companies(first: 10, trashed: ONLY ) {
    edges {
      node {
        id,
        vat,
        name
      }
    }
  }
}

Of course we would store the Trash enum, so users don't have to define that themself.

DataLoaders, DataFetchers, and non Relay?

I'll make this one quick!

  1. Can we use the DataLoaders/DataFetchers without Relay?
  2. Any idea on time for documentation on these features? I've noticed you've moved into subscriptions but gitbook still doesn't have these documented. I tried looking in the tests but couldn't really understand it.
  3. Do you have an example project? Normally when devs work on things like this they'll have like a todo app they build along the way that they add the features into. Do you have an app like that you can share which would be a decent reference since documentation takes time?

Cheers

Do we need to revisit the pagination cursors?

I think we need to revisit the pagination and connections as a whole in lighthouse, there's been a few changes in Laravel 5.4 that makes things easier, such as the Relation becoming macroable so we're able to add the toConnection() macro to that as well.

Additionally there is now a new method on Eloquent - forPageAfterId which should work well as it's effectively cursor pagination in a nutshell.

Now the current cursor generation doesn't seem right to me, I've found things like if I ask for the first 1, and keep incrementing the cursor then I get items 1, 2, 3, 5 and it goes out of whack from there (note this is contiguous data, IDs 1-200 are there).

This seems to come from a disconnect between how we generate the cursor for pagination e.g. here https://github.com/nuwave/lighthouse/blob/master/src/Support/Definition/PageInfoType.php#L73

And how we decode the cursor e.g. here https://github.com/nuwave/lighthouse/blob/master/src/Support/Traits/GlobalIdTrait.php, which seem to expect just type:id causing the effect above.

I'm proposing that we standardize the cursors to be graphqlType:cursorColumn:cursorColumnValue

So the 5th item from a graphql type if user would look like user:id:5
This means that to get the items we can just do e.g.

function resolve($args){
   return User::orderBy('created_at', 'desc')->toConnection($args);

   //or if we didn't want to alter the query...
   return User::getQuery()->toConnection($args);
}

//this is the macro definition
function toConnection($args){
    list($type, $column, $value) = $this->decodeCursor($args);
    $first  = isset($args['first']) ? $args['first'] : 15;
    $items = $this->forPageAfterId($first, $column, $value)->get();
    $total = $this->count();
    return new LengthAwarePaginator($items, $total, $first);
}

Thoughts?

Support for Query Complexity Analysis

webonyx/graphql-php has support for query complexity analysis. It would be helpful if there was a @complexity directive that allowed you to set a individual field, and for the paginators to set the complexity to a function that returns the number of results its going to return multiplied by the child complexity, as shown in the example at https://webonyx.github.io/graphql-php/security/

Need a directive for a single model query

Right now if we're doing a query for multiple models we have the fantastic @paginate directive.
Unfortunately I cannot find anything similar for a single model.

Do we need to add a new @find(model: "App\\User") directive to allow the following

type Query {
    users(name: String @where(operator: "like"), id: ID @in): [User!]! @paginate(model: "App\\User")
    user(id: ID @eq, email: String @eq): User @find(model: "App\\User")
}

Trouble retrieving a date as string - "String cannot represent non scalar value: instance of Illuminate\\Support\\Carbon"

Hey,

I have started building my first project with Lighthouse.

It's amazingly fast way to building apps. Still, I'm running into an issue with retrieving a string Date representation. I have inserted a new enrty into the database through a mutation.

This is the error that gets returned:
"String cannot represent non scalar value: instance of Illuminate\\Support\\Carbon"

Here is the schema file I'm using:

# schema.graphql

type Project {
    id: ID!
    parent_id: Parent @belongsTo
    name: String!
    created_at: String
    updated_at: String
    deleted_at: String
}

type Query {
    projects: [Project!]! @field(resolver: "App\\Http\\GraphQL\\ProjectQueries@index")
}

As can be seen from artisan tinker, the date is present on the data instance:
screen shot 2018-04-10 at 13 57 30

And the screenshot from GraphQL Playground:
screen shot 2018-04-10 at 13 21 24

Am I doing it wrong or is that an issue that needs additional work on your end?

Thank you again for this package & the work you're doing.

Update at feb 2018

Hi there,

How we getting on this project, seems its been left aside from here.

Looking for Relay, as the Folkloreatelier/laravel-graphql seems very active and I have been using it, Relay does not seem to be their focus.

I know that some of you are moving to Typescript and the lovely async functions, probably looking for the subscriptions, but ill like to continue using Laravel.

Any comments will be gratefully appreciated.

Progress

Hey, thanks dir the work on this. Would you recommend to use your Old package or do you think this One coukd be ready soon?
I don't mean by any means to Stress, but Just out of interest.
Starting a new Project in about a month and I am thinking about using relay.

Fetching relationships gives SQLSTATE[42601] error

Hello,
I was following the walkthrough for lighthouse on youtube, but I am running onto SQLSTATE error when I want to use relationships.

This is my schema.graphql file:

enum Type {
    ADMIN @enum(value: "admin")
    CUSTOMER @enum(value: "customer")
}

type User {
    id: ID!
    name: String!
    email: String!
    type: Type!
    created_at: String!
    updated_at: String
}

type Customer {
    id: ID!
    email: String!
    phone: String
    user: User @belongsTo
}

type Query {
    customers: [Customer!]! @field(resolver: "App\\Http\\GraphQL\\Query@customers")
}

When I call this query:

{
  customers {
    id
    user {
      name
    }
  }
}

The return values are:

{
  "data": {
    "customers": [
      {
        "id": "1",
        "user": null
      }
    ]
  },
  "errors": [
    {
      "message": "SQLSTATE[42601]: Syntax error: 7 ERROR:  syntax error at or near \".\"\nLINE 1: SELECT `users`.* FROM ((select * from \"users\" where \"users\"....\n                      ^ (SQL: SELECT `users`.* FROM ((select * from \"users\" where \"users\".\"id\" in (1))) AS `users`)",
      "locations": [
        {
          "line": 4,
          "column": 5
        }
      ]
    }
  ]
}

And laravel.log contains the following info:

[2018-04-24 02:54:08] local.INFO: GraphQL Error: {"code":0,"message":"SQLSTATE[42601]: Syntax error: 7 ERROR:  syntax error at or near \".\"
LINE 1: SELECT `users`.* FROM ((select * from \"users\" where \"users\"....
                      ^ (SQL: SELECT `users`.* FROM ((select * from \"users\" where \"users\".\"id\" in (1))) AS `users`)","trace":"#0 /home/vagrant/code/kalsha/vendor/webonyx/graphql-php/src/Executor/Executor.php(850): GraphQL\\Error\\Error::createLocatedError(Object(Illuminate\\Database\\QueryException), Object(ArrayObject), Array)
#1 /home/vagrant/code/kalsha/vendor/webonyx/graphql-php/src/Executor/Promise/Adapter/SyncPromise.php(144): GraphQL\\Executor\\Executor->GraphQL\\Executor\\{closure}(Object(Illuminate\\Database\\QueryException))
#2 /home/vagrant/code/kalsha/vendor/webonyx/graphql-php/src/Executor/Promise/Adapter/SyncPromise.php(35): GraphQL\\Executor\\Promise\\Adapter\\SyncPromise->GraphQL\\Executor\\Promise\\Adapter\\{closure}()
#3 /home/vagrant/code/kalsha/vendor/webonyx/graphql-php/src/Executor/Promise/Adapter/SyncPromiseAdapter.php(140): GraphQL\\Executor\\Promise\\Adapter\\SyncPromise::runQueue()
#4 /home/vagrant/code/kalsha/vendor/webonyx/graphql-php/src/GraphQL.php(236): GraphQL\\Executor\\Promise\\Adapter\\SyncPromiseAdapter->wait(Object(GraphQL\\Executor\\Promise\\Promise))
#5 /home/vagrant/code/kalsha/vendor/nuwave/lighthouse/src/GraphQL.php(122): GraphQL\\GraphQL::executeAndReturnResult(Object(GraphQL\\Type\\Schema), '{\
  customers {...', NULL, Object(Nuwave\\Lighthouse\\Schema\\Context), NULL)
#6 /home/vagrant/code/kalsha/vendor/nuwave/lighthouse/src/GraphQL.php(81): Nuwave\\Lighthouse\\GraphQL->queryAndReturnResult('{\
  customers {...', Object(Nuwave\\Lighthouse\\Schema\\Context), NULL, NULL)
#7 /home/vagrant/code/kalsha/vendor/nuwave/lighthouse/src/Support/Http/Controllers/GraphQLController.php(44): Nuwave\\Lighthouse\\GraphQL->execute('{\
  customers {...', Object(Nuwave\\Lighthouse\\Schema\\Context), NULL)
#8 [internal function]: Nuwave\\Lighthouse\\Support\\Http\\Controllers\\GraphQLController->query(Object(Illuminate\\Http\\Request))
#9 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Routing/Controller.php(54): call_user_func_array(Array, Array)
#10 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): Illuminate\\Routing\\Controller->callAction('query', Array)
#11 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Routing/Route.php(212): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(Nuwave\\Lighthouse\\Support\\Http\\Controllers\\GraphQLController), 'query')
#12 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Routing/Route.php(169): Illuminate\\Routing\\Route->runController()
#13 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Routing/Router.php(659): Illuminate\\Routing\\Route->run()
#14 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(30): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#15 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(102): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#16 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Routing/Router.php(661): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))
#17 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Routing/Router.php(636): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))
#18 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Routing/Router.php(602): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))
#19 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Routing/Router.php(591): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))
#20 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(176): Illuminate\\Routing\\Router->dispatch(Object(Illuminate\\Http\\Request))
#21 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(30): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))
#22 /home/vagrant/code/kalsha/vendor/fideloper/proxy/src/TrustProxies.php(57): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#23 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(149): Fideloper\\Proxy\\TrustProxies->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#24 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#25 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(30): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#26 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(149): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#27 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#28 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(30): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#29 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(149): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#30 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#31 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#32 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(149): Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#33 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#34 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(46): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#35 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(149): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#36 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#37 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(102): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#38 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(151): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))
#39 /home/vagrant/code/kalsha/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(116): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))
#40 /home/vagrant/code/kalsha/public/index.php(55): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))
#41 {main}"} 

I am using PostgreSQL and running PHP 7.2.
How to get the relationships to work? I can't figure it out. Thanks for any help

RelayConnection::scopeGetConnection breaks seeders.

What is the issue?

The scope registered at
nuwave/lighthouse:/src/Support/Traits/RelayConnection.php#L18
conflicts with a built in laravel method at
laravel/framework:/src/Illuminate/Database/Eloquent/Model.php#L1005

Suggested fix?

so it looks like we need to change the scope name;
Might I suggest we go with scopeGetGraphQLConnection().

For consistency we should also rename scopeLoadConnection() to scopeLoadGraphQLConnection().

These names are fairly precise but should avoid conflicts in the future as anything to do with connection seems to be quite dangerous grounds in Laravel.

Thoughts?

exact error message below for "googlers" sake

[Symfony\Component\Debug\Exception\FatalThrowableError]
Type error: Too few arguments to function App\User::scopeGetConnection(), 1 passed in /var
/www/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php on line 930 and
exactly 2 expected

Note that the error is actually triggered from the factory(...)->create() method, however these are normally only used in seeders.

[Feat] Return model as original property on Response

Could be nice if we changed graphql()->execute($query) to return a Response object instead and setting the original property on the response to the original model.

By doing this we would have the opportunity for making tests which aren't dependent on our data structure, but instead do something like this

$user = factory(User::class)->create();
$this->be($user);
$query = "{me{email}}";
$response = graphql()->execute($query);
$this->assertTrue($user->is($response->getOriginalContent()));

This test will check if the endpoint me has gotten the correct user model, but it totally ignores what data is actually selected as we don't care about this in this test, just that it is the correct model.

[Feat] Error message from exceptions

Could be nice with an interface to define custom rendering of exceptions just like Laravels Illuminate\Contracts\Support\Responsable interface.

[Feat] Scout support

Thanks for supplying query to args directives, really helps alot!

So I am creating an Arg directive called @search for adding support for Laravel scout (fulltext search).

Is this something you would want in your package or should I make an extension for it?

Pagination on root fields.

Here you are something thats working for root fields.

this one works to create a Relay type [@]connection:

public function resolve()
 {
        $data = Car::orderBy('id', 'DESC')->relayConnection($this->args);
        $pageInfo = (new ConnectionField)->pageInfoResolver($data,$this->args,$this->context,$this->info);

        $page = $data->currentPage();
        $edges = $data->values()->map(function ($item, $x) use ($page) {
            $cursor = ($x + 1) * $page;
            $encodedCursor = $this->encodeGlobalId('Car', $cursor);
            $globalId = $this->encodeGlobalId('Car', $item->getKey());
            $item->_id = $globalId;
            return ['cursor' => $encodedCursor, 'node' => $item];
        });


        return [
            'pageInfo' => $pageInfo,
            'edges' =>  $edges,
        ];
    }

Swap to get the Paginator style.

->paginatorConnection($this->args);
        $pageInfo = (new PaginatorField)->paginatorInfoResolver($data,$this->args,$this->context,$this->info);

I believe this is something can go on a directive type for queries? where I'm only responsible to start with the initial query,

$data = Car::orderBy('id', 'DESC')
                    ->active('publicado')
                    ->notActive('vendido')

or a Model::query() if I got no arguments.

full relay query, (Im working now on the react-native this is why it comes with fragments, full day to build a root query with a QueryRenderer + createPaginationContainer, no docs around)

query carsQuery($count: Int!, $cursor: ID) {
  ...ItemList
}

fragment ItemList on Query {
  cars(first: $count, after: $cursor) {
    edges {
      cursor
      node {
        id
        ...Item_car
        __typename
      }
    }
    pageInfo {
      
      hasNextPage
      lastPage
          
      
    }
  }
}

fragment Item_car on Car {
  id
  title
  text
  updated_at
  media {
    img_small
    id
  }
}

params

{"count":3,"cursor":null}
``

Relationships with meta data

While asking one of my "How do I..." questions - specifically this one I realised this likely warrants some external discussion.

Right now I'm thinking that the ideal way to do this if we have some additional meta data is going to be manually setting up a link model e.g. UserCompanyLink and then rather than using belongsToMany use hasMany/belongsTo relations so a query would then look like

{
  users {
    data {
      id
      name
      companies {
        id #this is the relationship id
        role #this is one of the "pivot" fields
        company {
          id #this is the company id
          name
        }
      }
    }
  }
}

For mutations this gives you a lot of options, You could either do a mutation with the input like

{
  "id": 5,
  "name": "Donald Trump",
  "companies": [
    {"id": 8, "role": "owner"},
    {"id": 12, "role": "employee"}
  ]
}

And then assume that if the companies key is present it always represents the full list of companies the user is linked to.

The issue with this method is that a) it requires a custom resolver, b) you need to always pass across the full list of companies. The good thing is you can manage the relationships in bulk.

Alternatively you could treat the UserCompanyLink as a full entity and add createUserCompanyLink, deleteUserCompanyLink, and updateUserCompanyLink mutations.

This second method is likely what I'll go for, although I feel there might be a better way than skipping the belongsToMany relations in laravel and also it becomes a bit of a message in relay as your query looks like

{
  users {
    edges {
      cursor
      node {
        id
        name
        companies {
          edges {
            cursor
            node {
              id #this is the relationship id
              role #this is one of the "pivot" fields
              company {
                id #this is the company id
                name
              }
            }
          }
        }
      }
    }
  }
}

When really the ideal output in my mind would be this
(note I haven't actually thought this through from the caching side of frontend clients)

{
  users {
    edges {
      cursor
      node {
        id
        name
        companies {
          edges {
            cursor
            role #this is one of the "pivot" fields
            id #this is the relationship id
            node {
              id #this is the company id
              name
            }
          }
        }
      }
    }
  }
}

What's our thoughts around this?

Automatically resolve Connections

If I create a new connection and providing a FQC, It would be awesome if the ConnectionRegistrar checked if it was a class (class_exists) and tried to resolve it via the service container, before the instance is created.

public function fields() {
    return [
        'maps' => GraphQL::connection(MapConnection::class)->field()
    ];
}

It would make it possible for us to utilize the Dependency Injection in the Connection, instead of using the helper-function app to pull in necessary services and such.

Again, I would be happy to provide a PR for this.

Relay mutation to add edge to connection

This is more a question than a issue.

I have the following mutation. I want to return the edge from the server to added it to the connection, but i don't know how to returned.

Thanks.

CreateComment.js

class CreateComment extends Relay.Mutation {
  getConfigs() {
    return [{
      connectionName: 'replies',
      edgeName: 'commentEdge',
      parentID: this.props.replyToComment.id,
      parentName: 'game',
      rangeBehaviors: {
        '': 'append',
      },
      type: 'RANGE_ADD',
    }];
  }

  getFatQuery() {
    return Relay.QL`
      fragment on CreateCommentPayload {
        commentEdge
      }
    `;
  }

  getMutation() {
    return Relay.QL`mutation {createComment}`;
  }

  getVariables() {
    return {
      body: this.props.body,
      parentCommentId: this.props.replyToComment.id,
      subjectId: this.props.subject.id,
      subjectType: this.props.subject.type,
    };
  }
}

CreateCommentMutation.php

use GraphQL;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQL\Type\Definition\Type;
use Hub\Game;
use Nuwave\Lighthouse\Support\Definition\GraphQLMutation;
use Nuwave\Lighthouse\Support\Interfaces\RelayMutation;

class CreateCommentMutation extends GraphQLMutation implements RelayMutation
{
    /**
     * Attributes of mutation.
     *
     * @var array
     */
    protected $attributes = [
        'description' => '',
        'name'        => 'createComment',
    ];

    /**
     * Available arguments on mutation.
     *
     * @return array
     */
    public function args()
    {
        return [
            'body'            => [
                'name'  => 'body',
                'type'  => Type::nonNull(Type::string()),
                'rules' => ['required'],
            ],
            'parentCommentId' => [
                'name' => 'parentCommentId',
                'type' => Type::ID(),
            ],
            'subjectId'       => [
                'name'  => 'subjectId',
                'type'  => Type::nonNull(Type::ID()),
                'rules' => ['required'],
            ],
            'subjectType'     => [
                'name'  => 'subjectType',
                'type'  => Type::nonNull(Type::string()),
                'rules' => ['required'],
            ],
        ];
    }

    /**
     * List of output fields.
     *
     * @return array
     */
    public function outputFields()
    {
        return [
            'commentEdge' => [
                'type'    => function () {
                    return GraphQL::edge('comment');
                },
                'resolve' => function ($payload) {
                    return $payload;
                },
            ],
        ];
    }

    /**
     * Resolve the mutation.
     *
     * @param  array $args
     * @param  mixed $context
     * @param  ResolveInfo $info
     * @return mixed
     */
    public function mutateAndGetPayload(array $args, $context, ResolveInfo $info)
    {
        if ($args['subjectType'] == 'Game') {
            return $this->createGameComment($args);
        }
    }

    private function createGameComment($args)
    {
        $subjectId = $this->decodeRelayId($args['subjectId']);
        $parentCommentId = $args['parentCommentId'] ? $this->decodeRelayId($args['parentCommentId']) : null;

        return Game::findOrFail($subjectId)->comments()->create([
            'body'        => $args['body'],
            'parent_id'   => $parentCommentId,
            'provider_id' => auth('providers')->id(),
            'user_id'     => auth('users')->id(),
        ]);
    }
}

Subscriptions

Currently, this is just a placeholder for discussions. But as a quick progress report, I have gotten started on subscriptions this weekend and it's coming along quite nicely! Right now I have 2 variations in mind:

  1. Websockets (lighthouse-subscriptions-ws) - The main goal of this package is to keep everything in PHP land. The WS server will be built with Ratchet. I've tested some things out and I'm able to get Playground to connect/disconnect to a Ratchet server successfully (using the same methods as subscriptions-transport-ws). The next step is to start pushing down messages from the server. Since a subscriber can subscribe to multiple subscriptions (lol), I need storage. So it will launch w/ InMemory and Redis storage out of the box, but it can also be extended (i.e., MySQL storage). Because of how far along I am, this will likely be the first package released.

  2. Pusher (lighthouse-subscriptions-pusher) - Maintaining an websocket server for a massive project doesn't sound fun to me... so I want to include at least one third-party solution. graphql-ruby has a great solution for this, however, it does rely on a custom Link for Apollo to work with it. Relay Modern is mentioned too, but I haven't dived into the JS parts of that yet.

The coolest thing (I think) is the fact that I can create these packages completely separate from the main lighthouse repo by leveraging directives! So hopefully, the community will be able to create some great alternatives if you use a different 3rd party WS provider or if you have a solution that relies on something other than Ratchet (i.e., Node).

I currently don't have a timeline for this, it just being done after work hours and on the weekends but this weekend was pretty productive so I'm really hoping it won't be too long before I can get this in everyone's hands!

Initial Beta Release of lighthouse-ws

pageInfo total return null

When nesting connections I'm experiencing a problem with the PageInfo field.

When i try to execute this query:

query{
  users(first: 1){
    pageInfo{
      hasNextPage
      hasPreviousPage
      total
      endCursor
    }
    edges{
      node{
        id
        username
        news_articles(first: 2){
          pageInfo{
            hasNextPage
            hasPreviousPage
            total
          }
          edges{
            node{
              id
              headline
            }
          }
        }
      }
    }
  }
}

I get this response

{
  "data": {
    "users": {
      "pageInfo": {
        "hasNextPage": true,
        "hasPreviousPage": false,
        "total": 10,
        "endCursor": "YXJyYXljb25uZWN0aW9uOjE="
      },
      "edges": [
        {
          "node": {
            "id": "1",
            "username": "tspinka",
            "news_articles": {
              "pageInfo": {
                "hasNextPage": false,
                "hasPreviousPage": false,
                "total": null
              },
              "edges": [
                {
                  "node": {
                    "id": "1",
                    "headline": "Dignissimos voluptas eum facilis quas."
                  }
                },
                {
                  "node": {
                    "id": "2",
                    "headline": "Et architecto voluptatem vitae dolorem dolor."
                  }
                }
              ]
            }
          }
        }
      ]
    }
  }
}

The first level is working but the second isn't.

Here is my schema file

type NewsArticle {
    id: ID
    headline: String
    slug: String
    article: String
    author: User @belongsTo
    comments: [NewsArticleComment!]! @hasMany(type: "relay")
}

type NewsArticleComment {
    id: ID
    comment: String
    author: User @belongsTo
    news_article: NewsArticle @belongsTo
}

type User {
    id: ID
    username: String
    email: String
    runescape_name: String
    member: Boolean
    news_articles: [NewsArticle!]! @hasMany(type: "connection", relation: "newsArticles")
}

type Query {
    users: [User!]! @paginate(type: "relay", model: "\\App\\User")
    news_articles: [NewsArticle!]! @paginate(type:"relay", model: "\\App\\NewsArticle")
}

Multiple directives

I'm making a little test app where i have this schema

type NewsArticle {
    id: ID
    headline: String
    slug: String
    article: String
    author: User @belongsTo
    comments: [NewsArticleComment!] @hasMany
}

type NewsArticleComment {
    id: ID
    comment: String
    author: User @belongsTo
    news_article: NewsArticle @belongsTo
}

type User {
    id: ID
    username: String
    newsArticles: [NewsArticle!] @hasMany @rename(attribute: "news_articles")
}

type Query {
    users: [User!]! @field(resolver: "App\\Http\\GraphQL\\Query@users")
    news_articles: [NewsArticle!]! @field(resolver: "App\\Http\\GraphQL\\Query@newsArticles")
}

The problem i'm having is the "newsArticle" field on the User type. I want to rename and tell that it is a hasMany relationship. Is there any way to do this?

No description in composer.json

There is no description for this package, making it hard to find on packagist. Doesn't show up if you search for graphql, for example.

https://docs.google.com/uc?id=1yGPXYHKwVf1K1E5FqD9DQNjsV_IC5Wfy

Argument filters are not optional

Take the following schema

type Query {
    me: User @auth
    users(
        name: String @where(operator: "like")
        id: ID @eq
    ): [User!]! @paginate(model: "App\\User")
}

I'd expect to be able to query

{
    users(name: "Dr%") {
        id
        name
    }
}

To be able to get all the users whose names start with "Dr".
Unfortunately due to id not being passed the query gets `AND "id" IS NULL" appended, Which obviously isn't what we want! We need to be able to query via just name or just id

Pagination directive + order results

Helo @chrissm79,

Im wondering how can I filter/order results on a pagination directive.
Like filter results with a query or exclude items by a field.

right now if I try to mix a pagination with a field gives me following waring:

Fields can only have 1 assigned resolver directive. cars has 2 resolver directives [paginate, field]

Am I missing something?

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.