Search code examples
node.jsasync-awaitnestjs

NestJS - Why Does Method Return Before Executing Code


I am very new to node and nest JS, and am having what has to be a very simple problem, but I can't figure it out. Basically, I have a service class wrapping DB calls, and a controller method that calls a service method. The problem is the method returns before executing the DB call. Here's the controller:

    @Get(':mapCountry')
  async getProductsByMapCountry(
    @Param() params: { customerId: string, mapCountry: string },
    @Query() query: QueryArgs
  ): Promise<any> {
    const customerId = params.customerId
    const mapCountry = params.mapCountry
    const args = getArgs(query)
    const limit = args.paginate
    const offset = args.page
    return this.productsService.getProductsByMapCountry(customerId, mapCountry, limit, offset)
  }

and here's the service method

async getProductsByMapCountry(customerId: string, mapCountry: string, limit: number, offset: number): Promise<any>{
    var products: any
    await this.pool.connect();
    const request = this.pool.request()
      .input('CustomerId', customerId)
      .input('MapCountry', mapCountry)
      .input('Limit', limit)
      .input('Offset', offset)
      .execute(`[dbo].[GetProductsByMapCountry]`, (err, result) => {
        const paging = result.recordsets[1][0] as paging;
        products = { 
          docs: result.recordsets[0],
          pages: paging.pages,
          total: paging.total,
          limit: limit,
          offset: offset
      };
      console.log(products);
    });
    return products;
  }

All the logic that hits the DB fires after the method returns. I know this has to be simple, but I just can't find the fix. Any help would be appreciated.


Solution

  • Your getProductsByMapCountry function returns a promise, and you want it to resolve with the products result. If your execute function returned a promise, you could await it, and this would chain the two promises together.

    But execute takes a callback function instead, which it calls when it's done. That callback has no connection to the promise that you're trying to return. So you need to connect them. You can do this by wrapping the execute call in a new promise, which resolves or rejects when the callback is called.

    async getProductsByMapCountry(customerId: string, mapCountry: string, limit: number, offset: number): Promise<any>{
        await this.pool.connect();
        return new Promise((resolve, reject) => {
            this.pool.request()
                .input('CustomerId', customerId)
                .input('MapCountry', mapCountry)
                .input('Limit', limit)
                .input('Offset', offset)
                .execute(`[dbo].[GetProductsByMapCountry]`, (err, result) => {
                    if (err) {
                        reject(err);
                        return;
                    }
                    const paging = result.recordsets[1][0] as paging;
                    resolve({
                        docs: result.recordsets[0],
                        pages: paging.pages,
                        total: paging.total,
                        limit: limit,
                        offset: offset
                    });
                });
        });
    }