algolia / gatsby-plugin-algolia

A plugin to push to Algolia based on graphQl queries
https://yarn.pm/gatsby-plugin-algolia
Apache License 2.0
178 stars 45 forks source link

Async transformer function brokes the code #73

Closed bolotskydev closed 4 years ago

bolotskydev commented 4 years ago

In queries object we have this transformer function, which, as you know, proves to be very helpful when it comes to preprocessing data that we want to send to Algolia side:

const queries = [
  {
    query: myQuery,
    transformer: ({ data }) => data.allSitePage.edges.map(({ node }) => node), // optional
    indexName: 'index name to target', // overrides main index name, optional
    settings: {
      // optional, any index settings
    },
    matchFields: ['slug', 'modified'], // Array<String> overrides main match fields, optional
  },
];

In readme we can read, that transformer could be an async function, but in reality passing an async function breaks the code completely.

Consider this situation in which I had intention to additionally process some of the fields using 3rd party libs (though I abstracted everything to ease understanding):

const someAsyncFn = async (rawBody) => useThirdParty(rawBody)

// adapt query results for algolia
const flatten = (arr) =>
  Promise.all(
    arr.map(async ({ children }) => {
      const postData = { ...children[0] };
       const text = await someAsyncFn(postData.rawBody);
      return {
        ...postData.frontmatter,
        content: text,
        objectID: postData.objectID,
      };
    }),
  );

const postsQuery = `{
 // query body
}`;

const queries = [
  {
    query: postsQuery,
    transformer: async ({ data }) => {
      const res = await flatten(data.posts.nodes);
      return res;
    },
    indexName: algoliaIndexName,
  },
];
module.exports = queries;

This lead to this error: image

If we proceed to the source code, here is exactly the place where it breaks:

 const objects = await transformer(result).map((object) => ({
      objectID: object.objectID || object.id,
      ...object,
    }));

I think this is a bug and a .map method should not be chained right away since there could be no mappable object at all, just like in the case above, where after evaluation we have something like:

const objects = await Promise<any>.map(...)

Which is the main cause of crashing.

If you could separate transform and map steps into 2, everything would work as expected:

 const objectsData = await transformer(result);

const objects = objectsData.map((object) => ({
      objectID: object.objectID || object.id,
      ...object,
    }));

Here is the fiddle with everything I've just tried to explain.

Please, let me know if I had misunderstood something and a bug actually hides in my code or if I should provide more information related to this issue.

bolotskydev commented 4 years ago

Resolved in #76

Haroenv commented 4 years ago

Thanks for noticing this, @tedsczelecki has found a solution for this already and is released in version 0.11.1.