graphql-compose / graphql-compose-elasticsearch

Hide Elastic Search REST API behind GraphQL.

Home Page:https://graphql-compose.herokuapp.com/elasticsearch/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

elastic query generated for sort by enum

amarflybot opened this issue · comments

@nodkz , I see a small issue with the elastic query generated at version:

Wrong query produced for sort: [order_id__asc],, where order_id__asc is a enum.

After the change made in #214, Elastic Query generated was

 "sort": [
      "order_id__asc"
    ]

Before the change in #214
Correct query generated was:

 "sort": [
      {
        "order_id": "asc"
      }
    ]

Originally posted by @amarflybot in graphql-compose/graphql-compose#214 (comment)

Sort functionality for the below code works fine:

const generatedSchema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'Query',
    fields: {
      ecommerceSearch: EcommerceEsTC.getResolver('search').getFieldConfig(),
      ecommercePagination: EcommerceEsTC.getResolver('searchPagination').getFieldConfig(),
      ecommerceSearchConnection: EcommerceEsTC.getResolver('searchConnection').getFieldConfig()
    },
  }),
});

const server = new ApolloServer({
  schema: buildFederatedSchema(generatedSchema)
});

The above code generates the sort:

"sort": [
      {
        "order_id": "asc"
      }
    ]

The new code:

const extensionSdl = gql` 
  extend type Content @key(fields: "id") {
    id: ID! @external
    ecommerces: [ecommerceecommerce]
  }

  extend type Director @key(fields: "id") {
    id: ID! @external
    geoips: [ecommerceecommerceGeoip]
  }
`;

function findEcommerceByContentId(id: number) {

}

const resolvers = {
  Content: {
    ecommerces(content) {
      console.log(content);
      return findEcommerceByContentId(content.id);/*find ecommerces by content id*/
    }
  },
  Director: {
    geoips(content) {
      console.log(content);
      return findEcommerceByContentId(content.id);/*find ecommerces by content id*/
    }
  }
};

let composer = schemaComposer.toSDL({exclude: ['Boolean','String']});
const app = express();
let resolveMethods = schemaComposer.getResolveMethods();
const server = new ApolloServer({
  schema: buildFederatedSchema([
      {typeDefs: gql(composer), resolvers: resolveMethods},
      {typeDefs: extensionSdl, resolvers: resolvers}
      ])
});

Generates the wrong code:

"sort": [
      "order_id__asc"
    ]

I've just updated dependencies and this lib correctly works with new graphql-compose 7.11.0. It passes all tests. The error somewhere in graphql-compose methods or in a way how we combine schemas.

Will be nice if you create a PR with error in graphql-compose repo like graphql-compose/graphql-compose#234 It will be nice if you try to write such test case without using graphql-compose-elasticsearch package.

I need a ready test-case for debugging. When I can write such test-case myself... I don't know (don't have enough free time).

Thanks for the quick reply, I am trying to farmalize the test, will raise the PR.
I am still figuring where from graphql-compose it find the arguments for sort.

graphql-compose just bunch of helpers for graphql types modification. Other plugins, like graphql-compose-mongoose reads some models, mappings and generates according to their information the graphql types using graphql-compose methods.

Hi @nodkz , I have being debugging the graphql-compose and graphql-compose-elastic for a very long time now. But still can't find the place or method that resolves sort: [order_id__asc] to

"sort": [
      {
        "order_id": "asc"
      }
    ]

Could you please point me in right direction? I think somehow let resolveMethods = schemaComposer.getResolveMethods({exclude: ['Boolean', 'String', 'ID']});
is responsible.

in the code of Resolver.js:

    const resolve = this.getResolve();
    return (source, args, context, info) => {
      let projection = (0, _projection.getProjectionFromAST)(info);

      if (this.projection) {
        projection = (0, _deepmerge.deepmerge)(projection, this.projection);
      }

      if (opts.projection) {
        projection = (0, _deepmerge.deepmerge)(projection, opts.projection);
      }

      return resolve({
        source,
        args,
        context,
        info,
        projection
      });
    };
  }

Who populates args ?

In this case (source, args, context, info) all params are populated by graphql itself. So if you provide via graphql-query sort: [order_id__asc] arg then it transformed internally be Enum type. Enums in graphql has keys and values. So from client-side you work with keys but on the server-side in args your will get values from enums.

There is the code which generates SortEnum with keys and values

sortableFields.forEach(fieldName => {
const dottedName = fieldName.replace(/__/g, '.');
values[`${fieldName}__asc`] = {
value: { [dottedName]: 'asc' },
};
values[`${fieldName}__desc`] = {
value: { [dottedName]: 'desc' },
};
});

I worked with elastic about two years ago and for me, it's quite difficult to answer and solve problems. Many things already were forgotten. For now i just keep this lib in sync with graphql-compose changes and improvements. And I will be happy if somebody can bring new features and improvements.

image

Uploading a pic that shows in debugging that Sort.js works as it is intended. But still when the Graphql populates (source, args, context, info) it popluates args.sort with wrong value: "order_id__asc"

I've just added graphql query test for EnumTypeComposer:

https://github.com/graphql-compose/graphql-compose/blob/5f5ce3a68c95c3ddd91dc897cd13907327c47a57/src/__tests__/EnumTypeComposer-test.js#L412-L434

graphql-compose works correctly. It looks like the problem somewhere in this package. Maybe in resolvers which make calls to elastic.

The tests are fine.
I tried debugging line by line for Elastic Library, everything looks fine.
All Sort Enums are having right values: "labels__timestamp__closed__desc":{"value":{"labels.timestamp.closed":"desc"}}

But Still when the request comes for Sort by labels__timestamp__closed__desc, Somehow the values is changed to labels__timestamp__closed__desc, instead of {"labels.timestamp.closed":"desc"}

To Replicate:
In Elastic Execute the query:

POST bug_reports/_doc/1
{
  "title": "Results are not sorted correctly.",
  "labels": {
    "priority": "urgent",
    "release": ["v1.2.5", "v1.3.0"],
    "timestamp": {
      "created": 1541458026,
      "closed": 1541457010
    }
  }
}

Reference index file: https://github.com/amarflybot/graphql-compose-apollo-federation/blob/8bde66dc00ffa6a6c6ed1d69ff3d7a21a8d0eb32/src/index.ts#L129

Agggr, I think that I gotcha your problem.
You are using apollo federation. So you're extracting types as SDL & resolvers. And then pass them to buildFederatedSchema which reconstructs the schema from scratch. But graphql-compose does not extract values from Enums in getResolveMethods() method. See https://www.apollographql.com/docs/graphql-tools/scalars/#internal-values for more details.

I'll make a fix to graphql-compose for solving this problem.

Please try new graphql-compose (7.12.1). It should fix your problem.

@nodkz , Thanks this fixes the issue.

With some minor errors.

[
    {
      "message": "Int cannot represent non-integer value: { value: 1, relation: \"eq\" }",
      "locations": [
        {
          "line": 3,
          "column": 5
        }
      ],
      "path": [
        "bgSearchConnection",
        "count"
      ],
      "extensions": {
        "code": "INTERNAL_SERVER_ERROR",
        "exception": {
          "stacktrace": [
            "TypeError: Int cannot represent non-integer value: { value: 1, relation: \"eq\" }",
            "    at GraphQLScalarType.serializeInt [as serialize] (/Users/amarendrakumar/sandbox/cal-search-service/node_modules/graphql/type/scalars.js:43:11)",
            "    at completeLeafValue (/Users/amarendrakumar/sandbox/cal-search-service/node_modules/graphql/execution/execute.js:635:37)",
            "    at completeValue (/Users/amarendrakumar/sandbox/cal-search-service/node_modules/graphql/execution/execute.js:579:12)",
            "    at completeValueCatchingError (/Users/amarendrakumar/sandbox/cal-search-service/node_modules/graphql/execution/execute.js:495:19)",
            "    at resolveField (/Users/amarendrakumar/sandbox/cal-search-service/node_modules/graphql/execution/execute.js:435:10)",
            "    at executeFields (/Users/amarendrakumar/sandbox/cal-search-service/node_modules/graphql/execution/execute.js:275:18)",
            "    at collectAndExecuteSubfields (/Users/amarendrakumar/sandbox/cal-search-service/node_modules/graphql/execution/execute.js:713:10)",
            "    at completeObjectValue (/Users/amarendrakumar/sandbox/cal-search-service/node_modules/graphql/execution/execute.js:703:10)",
            "    at completeValue (/Users/amarendrakumar/sandbox/cal-search-service/node_modules/graphql/execution/execute.js:591:12)",
            "    at /Users/amarendrakumar/sandbox/cal-search-service/node_modules/graphql/execution/execute.js:492:16"
          ]
        }
      }
    }
  ],

I will check this in some time.

The above issue is because of data. Please close the ticket. Thanks a lot.