1
votes

I am developing a web application that queries an OrientDB Graph Database using GraphQL. It uses Apollo Server to resolve incoming GraphQL queries.

I want to build a query that will simply return the 'name' field for each "Topic" Object as a list of Strings. e.g.:

{
  "data": {
    "allTopicNames": [
      "Topic 1",
      "Topic 2",
      "Topic 3",
      "Topic 4"
    ]
  }
}

To do so, I created a Type Definition:

// Imports: GraphQL
import { gql } from 'apollo-server-express';

// GraphQL: TypeDefs
const TYPEDEFS = gql`
type Query {
    allTopics: [Topic]
    topic(name: String): [Topic]
    allTopicNames: [String] //This is the new Type Definition -- we want a list of Strings
  }
type Topic {
    name: String
}
`;

// Exports
export default TYPEDEFS;

And the associated Resolver:

//Connect to OrientDB
var OrientJs = require('orientjs');

var server = OrientJs({
    host: "localhost",
    port: "2424",
    username: "root",
    password: "root"
});

var db = server.use({
    name: 'database',
    username: 'root',
    password: 'root'
});

// GraphQL: Resolvers
const RESOLVERS = {
    Query: {
        allTopics: () => {
            return db.query('SELECT FROM Topic ORDER BY name');
        },
        allTopicNames: () => {
            return db.query('SELECT name FROM Topic ORDER BY name'); //This is the new resolver
        },
        topic: (obj, args) => {
            return db.query('SELECT FROM Topic WHERE name=\'' + args.name + '\' LIMIT 1');
        }
    }
};

// Exports
export default RESOLVERS;

However, when I try to implement the above Type Definition and Resolver, I receive a list of strings which are all "[object Object]" instead of the actual strings:

{
  "data": {
    "allTopicNames": [
      "[object Object]",
      "[object Object]",
      "[object Object]",
      "[object Object]"
    ]
  }
}

I tried to add some code to the resolver that would iterate through each object and create a proper list of Strings to return:

// GraphQL: Resolvers
const RESOLVERS = {
    Query: {
        allTopics: () => {
            return db.query('SELECT FROM Topic ORDER BY name');
        },
        allTopicNames: () => {
            let the_list_of_records = db.query('SELECT name FROM Topic ORDER BY name').then(res => { 
                let the_list_of_names = []; //We'll return a List of Strings using this
                for(var i = 0; i < res.length; i++){
                    the_list_of_names.push(res[i]['name']);
                }
                console.log(the_list_of_names);
                return the_list_of_names;
            });
        },
        topic: (obj, args) => {
            return db.query('SELECT FROM Topic WHERE name=\'' + args.name + '\' LIMIT 1');
        }
    }
};

But this didn't work, resulting in a null value being returned instead:

{
  "data": {
    "allTopicNames": null
  }
}

I'm frankly confused as to why I can't get a simple list of Strings to populate via this resolver. Perhaps I'm missing something obvious -- any insight is greatly appreciated!

1

1 Answers

1
votes

Your initial approach didn't work as expected because you were returning an array of objects. Your second attempt returns null because you don't return anything inside your resolver. Your resolver should always return a value or a Promise that will resolve to that value, otherwise the resolved value for the field will always be null.

The value of the_list_of_records will be a Promise, so you can just return that and that should be sufficient. But we can make this code a little easier to read using map like this:

allTopicNames: () => {
  return db.query('SELECT name FROM Topic ORDER BY name').then(res => {
    return res.map(topic => topic.name)
  })
}

// using async/await
allTopicNames: async () => {
  await topics = await db.query('SELECT name FROM Topic ORDER BY name')
  return topics.map(topic => topic.name)
}