Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Relay Error 'Object has no method find'

I've been working with reactjs a fair bit and thought I'd start playing around with graphql and relay. I've hit an error that I can't get to the bottom of, so I wondered if anyone on here may have encountered the same. Any pointers or ideas would be welcomed.

The error I am getting is

Error: GraphQL validation/transform error ``Object  has no method 'find'`` in file `/Users/chris/Documents/App/site/js/main.js`.

So I have a GraphQL server running and everything works fine I can query the backend database (I'm using mongodb) and the following query produces the correct results through the graphql ui

{
  store{
    items{
        _id
        title
        sub
    }
  }
}

produces the following output which is correct

{
  "data": {
    "store": {
      "items": [
        {
          "_id": "56e2c71d150040c491c73b26",
          "title": "Test Item One",
          "sub": "sub title here"
        }
      ]
    }
  }
}

So I think its safe to assume the the graphql server is fine and the problem must be with my implementation of relay or the babelRelayPlugin.js

The following is the main.js file with the render method simplified.

import React from 'react';
import Relay from 'react-relay';


class Main extends React.Component {

    render(){
        return (
            <div>
                <p>Test</p>
            </div>
        );
    }
}

Main = Relay.createContainer(Main, {
    fragments:{
        store: () => Relay.QL`
            fragment on Store {
                items {
                    title,
                }
              }
           `
    }
});

export default Main;

The following is the App.js file

import React from 'react';
import ReactDOM from 'react-dom';
import Relay from 'react-relay';
import Main from './main'

//React.render(<Main />, document.getElementById('react-main-mount'));

class HomeRoute extends Relay.Route {
    static routeName = 'Home';
    static queries = {
        store:(Component) => Relay.QL`
        query MainQuery {
            store { ${Component.getFragment('store')}}
        }`
    }
};

ReactDOM.render(<Relay.RootContainer 
                    Component={Main} 
                    route={new HomeRoute()} 
                />, 
                document.getElementById('react-main-mount')
               );

For completeness here is the schema.js I'm using.

import { GraphQLSchema, 
         GraphQLObjectType,
         GraphQLList,
         GraphQLInt,
         GraphQLString
       } from 'graphql';

// Schema allows us to use node feature to link the schema to the database
let Schema = (db) => {
let store = {};

let storeType = new GraphQLObjectType({
    name:'Store',
    fields:() => ({
        items: {
            type: new GraphQLList(itemType),
            resolve:() => db.collection("Item").find({}).toArray()
        }
    })
});

let itemType = new GraphQLObjectType({
    name: 'Item',
    fields:() =>({
        _id:{type: GraphQLString},
        title: {type: GraphQLString},
        sub:{type:GraphQLString},
        type:{type:GraphQLString},
        comments:{type:GraphQLInt}
    })
});

let schema = new GraphQLSchema({
    query: new GraphQLObjectType({
        name:'Query',
        fields: () => ({
            store: {
                type: storeType,
                resolve: () => store
            }

        })
    }),
});
    return schema;
};
export default Schema;

which is converted to JSON on by the server shown here

let app = express();
app.use(express.static('site')); // public folder

console.log("Starting Server");
//mongo url is the server 
(async () => {
    try{
    let db = await MongoClient.connect("mongodb://localhost:27017/App");
    let schema = Schema(db); 

    app.use('/graphql', GraphQLHTTP({
        schema,
        graphiql:true
    }));

  app.listen(3000, () => console.log('listening on port 3000'));  

  // Generate Schema
  let json = await graphql(schema, introspectionQuery); 
  fs.writeFile('./database/schema.json', JSON.stringify(json,null,2), err => {
      if(err) throw err;
      console.log("JSON schema created");
  });
    }catch(e){
        console.log(e);
    }
})();

And the babelRelayPlugin.js is below

var getBabelRelayPlugin = require('babel-relay-plugin');
var schemaData = require('./database/schema.json').data;
module.exports = getBabelRelayPlugin(schemaData);

And Webpack.config

module.exports = {
    entry:'./site/js/app.js',
    output:{
        path: __dirname + "/site",
        filename: "bundle.js"
    },
    module:{
        loaders:[
            {test:/\.js$/, exclude:/node_modules/, loader: 'babel-loader',
             query: {presets: ['react', 'es2015', 'stage-0'],
                     plugins: ['./babelRelayPlugin']
                    }
            }
        ]
    }
}

UPDATE: So I've had a little play around and the problem lies in the main.js RelayQL statement

Main = Relay.createContainer(Main, {
        fragments:{
            store: () => Relay.QL`
                fragment on Store {
                    items {
                        title,
                    }
                  }
               `
        }
    });

I commented out the code in app.js and replaced it with the following code as a test to see if basic a basic relay query worked and it did by returning the correct output to the console

ReactDOM.render(<Main />, document.getElementById('react-main-mount'));
console.log(Relay.QL`query store { store{ items {title}}}`);

So as I mentioned above the issue must be I suspect with the really statement in main.js, now the question is why?

For total completeness I have included the full error stack trace below

-- Relay Transform Error -- main --

File:  /Users/chris/Documents/App/site/js/main.js
Error: TypeError: Object  has no method 'find'
    at new RelayQLFragment (/Users/chris/Documents/App/node_modules/babel-relay-plugin/lib/RelayQLAST.js:143:49)
    at RelayQLTransformer.processDocumentText (/Users/chris/Documents/App/node_modules/babel-relay-plugin/lib/RelayQLTransformer.js:156:16)
    at RelayQLTransformer.transform (/Users/chris/Documents/App/node_modules/babel-relay-plugin/lib/RelayQLTransformer.js:67:29)
    at PluginPass.TaggedTemplateExpression (/Users/chris/Documents/App/node_modules/babel-relay-plugin/lib/getBabelRelayPlugin.js:124:36)
    at newFn (/Users/chris/Documents/App/node_modules/babel-traverse/lib/visitors.js:262:19)
    at NodePath._call (/Users/chris/Documents/App/node_modules/babel-traverse/lib/path/context.js:63:18)
    at NodePath.call (/Users/chris/Documents/App/node_modules/babel-traverse/lib/path/context.js:47:17)
    at NodePath.visit (/Users/chris/Documents/App/node_modules/babel-traverse/lib/path/context.js:93:12)
    at TraversalContext.visitQueue (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:146:16)
    at TraversalContext.visitSingle (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:115:19)
    at TraversalContext.visit (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:178:19)
    at Function.traverse.node (/Users/chris/Documents/App/node_modules/babel-traverse/lib/index.js:135:17)
    at NodePath.visit (/Users/chris/Documents/App/node_modules/babel-traverse/lib/path/context.js:103:22)
    at TraversalContext.visitQueue (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:146:16)
    at TraversalContext.visitMultiple (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:110:17)
    at TraversalContext.visit (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:176:19)
    at Function.traverse.node (/Users/chris/Documents/App/node_modules/babel-traverse/lib/index.js:135:17)
    at NodePath.visit (/Users/chris/Documents/App/node_modules/babel-traverse/lib/path/context.js:103:22)
    at TraversalContext.visitQueue (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:146:16)
    at TraversalContext.visitSingle (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:115:19)
    at TraversalContext.visit (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:178:19)
    at Function.traverse.node (/Users/chris/Documents/App/node_modules/babel-traverse/lib/index.js:135:17)
    at NodePath.visit (/Users/chris/Documents/App/node_modules/babel-traverse/lib/path/context.js:103:22)
    at TraversalContext.visitQueue (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:146:16)
    at TraversalContext.visitSingle (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:115:19)
    at TraversalContext.visit (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:178:19)
    at Function.traverse.node (/Users/chris/Documents/App/node_modules/babel-traverse/lib/index.js:135:17)
    at NodePath.visit (/Users/chris/Documents/App/node_modules/babel-traverse/lib/path/context.js:103:22)
    at TraversalContext.visitQueue (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:146:16)
    at TraversalContext.visitMultiple (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:110:17)
like image 228
Kraken18 Avatar asked Mar 13 '16 14:03

Kraken18


1 Answers

In your HomeRoute:

class HomeRoute extends Relay.Route {
    static routeName = 'Home';
    static queries = {
        store:(Component) => Relay.QL`
        query MainQuery {
            store { ${Component.getFragment('store')}}
        }`
    }
};

Have you tried just:

    static queries = {
        store:() => Relay.QL`
        query MainQuery {
            store
        }`
    }
like image 77
nethsix Avatar answered Oct 24 '22 23:10

nethsix