0

I'm trying to write a query builder similar to the query builder in Laravel but for TypeScript but I have come across a problem with a promise resolving.

In this code below I have cut down my builder and controller classes. Using this library https://github.com/mysqljs/mysql, I run a query using the code connection.query(...) which I pass in a callback function which processes the response and resolves/rejects accordingly. The thing I don't understand is that it reaches the console.log and outputs it into my console but the .then() in the controller is not being called.

import * as mysql from 'mysql';

interface InternalQueryReturnType<T> {
  results: T;
  fields?: mysql.FieldInfo[];
}

// Cut down version of my builder.
export class MySQLBuilder implements IQueryBuilder {
  protected query<T>(query: string): Promise<InternalQueryReturnType<T>> {
    return new Promise((resolve, reject) => {
      const connection = mysql.createConnection({
        host: 'localhost',
        user: 'root',
        password: '',
        database: 'dbname',
        port: 999,
      });

      connection.connect({}, (error) => {
        reject(error);
      });

      connection.query(query, (error, results, fields) => {
        if (error) {
          reject(error);
          return;
        }

        // It is reaching this point.
        console.log({ results }); // <- This is returning the correct results.
        resolve({ results, fields });
      });

      connection.end();
    });
  }
}

// My controller.
export class PostController {
  public static index(request: IRequest): Promise<IResponse> {
    return new Promise((resolve, reject) => {
      return new Promise((resolve) => {
        // Testing the raw query which the builder created.
        new MySQLBuilder().query<any>('SELECT * FROM `users` WHERE `id` = 1 LIMIT 1 OFFSET 0')
          .then(({ results }) => {
            // Nothing was passed into this.
            console.log({ results });
            resolve(new JsonResponse(results || {}));
          })
          .catch((error) => {
            resolve(new JsonResponse(error).status(400));
          });

        // Builder code.
        // new MySQLBuilder().table('users')
        //   .where('id', '=', 1)
        //   .first()
        //   .then((value: object | null) => {
        //     console.log(value);
        //     resolve(new JsonResponse(value || {}));
        //   })
        //   .catch((error) => {
        //     console.error({ error });
        //     resolve(new JsonResponse(error).status(400));
        //   });
      });
    });
  }
}

Has anyone experienced this issues with promises?

If you need the entire code base I can put it all up later but this should be enough code.

The solution to this issue was actually this:

connection.connect({}, (error) => {
  if (error) {
    reject(error);
  }
});
Isaac Skelton
  • 156
  • 1
  • 8
  • So the `.then` isn't being called. Is the `.catch` (that returns 400 error) being called? – CertainPerformance Nov 29 '19 at 00:00
  • Never mind, I'm a special snowflake. The problem was with `connection.connect() `not checking if error was null lol. – Isaac Skelton Nov 29 '19 at 00:02
  • Your many Promise constructors are odd and should be refactored https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it but if the code is as you've shown verbatim, they shouldn't be causing the issues here – CertainPerformance Nov 29 '19 at 00:04

1 Answers1

1

The solution to this issue was actually this:

connection.connect({}, (error) => {
  if (error) {
    reject(error);
  }
});

I wasn't checking if error was NULL.

Isaac Skelton
  • 156
  • 1
  • 8
  • Interesting. I'd consider that to be a bug with the `.connect` method. If there is an error, it *should* contain some sort of info. Most, like you, would think that a falsey error means that there's no error. – CertainPerformance Nov 29 '19 at 01:30
  • In their documentation it does show all the examples with catching the error and then throwing it. I would think it is to keep it consistent between functions which give more than one argument. E.g. `(error, results, fields)`. Although I'm thinking of looking for a different MySQL library since this one doesn't support prepared statements and I'm not going to push anything live like that. – Isaac Skelton Nov 29 '19 at 03:34