Search code examples
typescriptloopbackjs

How to force data filtering based on a parent ID, following an additional lookup on an API key in Loopback4/Typescript


I am a bit of a noob to Typescript and loopback(lb4) and I am at a sticking point, where I am pulling my hair a little and I am hopeful that the community may be able to assist. I am trying to complete a lookup for an record ID based on a API key that is against the database record, so I can then use this record as a foreign key for deriving another set of results from another database table. I am working with a preexisting database

Error showing as the below.

loopback:connector:mssql Result: null {"recordsets":[[]],"recordset":[],"output":{},"rowsAffected":[0]} +302ms /Users/bloop/Desktop/AngularTestFolder/ZaharaReporting/zaharareporting/dist/controllers/tenancy.controller.js:27 return object.tenancyid.valueOf; ^

TypeError: Cannot read property 'tenancyid' of null

I have tried a number of things and suspect that it is a lack of understanding some of the fundamentals of typescript or loopback4, so my apologies if this is the case, I am just finding myself going over the same ideas on how to get around it, so I feel in need of someone to point out why and how I am being stupid please.

I am trying to get the endpoint /api/{apikey}/GetSpecificBusinessunit' to work. but I am getting `FindTenancyID.IdOnly' coming back as undefined

import {
  repository,
} from '@loopback/repository';
import {
  param,
  get,
} from '@loopback/rest';
import { Tenancy, Businessunit } from '../models';
import { TenancyRepository, BusinessunitRepository } from '../repositories';

class TenancyHelper {
  constructor(@repository(TenancyRepository)
  public tenancyRepository: TenancyRepository) { }

  // Query filter tenancy to get Id only
  async idOnly(api: String) {
    return await this.tenancyRepository.findOne(
      { where: { apikey: api }, fields: { tenancyid: true }, limit: 1 },
      function (err: any, object: Tenancy) {
        //console.log("TenancyId was " + object.tenancyid);
        return object.tenancyid.valueOf;
      }).catch(a => console.log(a));
  }
}

export class TenancyController {
  constructor(
    @repository(TenancyRepository)
    public tenancyRepository: TenancyRepository,
    @repository(BusinessunitRepository)
    public businessunitRepository: BusinessunitRepository,
  ) { }


  @get('/api/{apikey}/GetSpecificBusinessunit', {
    responses: {
      '200': {
        description: 'Get BusinessUnit by API Key',
        content: { 'application/json': { schema: { 'x-ts-type': Businessunit } } },
      },
    },
  })
  async GetBusinessunit(
    @param.path.string('apikey') Apikey: String,
    FindTenancyId = new TenancyHelper(this.tenancyRepository),

  ): Promise<Businessunit[]> {
    return new Promise<Number>(function (resolve, reject) {
      Number(FindTenancyId.idOnly(Apikey));
    })
      .then(a => {
        console.log("This was the excecuted: " + a);
        return this.businessunitRepository.find(
          { where: { tenancyid: a } })
      })
  }

I expect a JSON object with a return of all business units with this tenancy API key defined in the path to be returned.


Solution

  • I wasn't using promises correctly(And possibly may not still), but this functions correctly for me

    In LoopBack 4, we avoid .then() and .catch() APIs in favor of await and regular try/catch blocks.

    export class TenancyController {
      //...
      async GetBusinessunit(
        @param.path.string('apikey') Apikey: String
      ): Promise<Businessunit[]> {
        const a = await this.tenancyRepository.findOne(
          { where: { apikey: Apikey }, fields: { tenancyid: true }, limit: 1 }
        );
    
        let id = -1;
        if (a !== null) {
          id = Number(a!.tenancyid);
        }
        return this.businessunitRepository.find(
          { where: { tenancyid: id } })
        });
      }
    }