All files / src/services locode.service.ts

34.15% Statements 14/41
0% Branches 0/8
12.5% Functions 1/8
30.77% Lines 12/39

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 1391x 1x 1x 1x     1x 1x   1x     1x 17x       17x   17x   17x                                                                                                                                                                                                                                          
import { bind, BindingScope } from '@loopback/core';
import { FilterBuilder, IsolationLevel, Options, repository } from '@loopback/repository';
import { validateValueAgainstSchema, HttpErrors } from '@loopback/rest';
import { omit } from 'lodash';
 
import { BaseResponses, Locode } from '@logchain/models';
import { CountryRepository, LocodeRepository } from '@logchain/repositories';
import { CSVParser, RecordsCreator, LocodeRow, locodeRowSchema, UploadFileType } from '@logchain/csv-parser';
import { LocodeDto } from '@logchain/dtos';
import { BaseService } from '.';
 
@bind({ scope: BindingScope.TRANSIENT })
export class LocodeService extends BaseService<Locode> implements RecordsCreator {
  headers = ['country_code', 'code', 'name', 'subdiv', 'function', 'status', 'iata', 'coordinates', 'remarks'];
 
  constructor(
    @repository(LocodeRepository)
    public locodeRepo: LocodeRepository,
    @repository(CountryRepository)
    public countryRepo: CountryRepository,
  ) {
    super();
  }
 
  /**
   * Get array Locode based on filter.
   * @param filter
   */
  async find(): Promise<BaseResponses<Locode>> {
    this.buildExtraFilterGetId(this.filter_builder);
 
    // allow get all locode
    // this.filter_builder.limit(Number.MAX_SAFE_INTEGER);
 
    return this.locodeRepo.findWithPaging(this.filter_builder.build());
  }
 
  /**
   * Build extra filter for Get locode
   * @param filterBuilder The filter builder instance
   * @return Filter
   */
 
  buildExtraFilterGetId(filterBuilder: FilterBuilder): FilterBuilder {
    filterBuilder.include({
      relation: 'country',
      scope: {
        fields: {
          id: true,
          name: true,
        },
      },
    });
 
    return filterBuilder;
  }
 
  /**
   * Builds the query for locode.
   * @param q The query string.
   */
  async buildSearchQuery(q?: string) {
    if (!q) {
      return;
    }
 
    const ilike_value = this.buildILikeValue(q);
    // FILTER: code OR name
    this.filter_builder.impose({
      or: [
        {
          code: ilike_value,
        },
        {
          name: ilike_value,
        },
      ],
    });
  }
 
  /**
   * Builds the query country for locode.
   * @param country The country id.
   */
  async buildCountryQuery(country?: number) {
    if (!country) {
      return;
    }
 
    // FILTER: country_id
    this.filter_builder.impose({
      or: [
        {
          country_id: country,
        },
      ],
    });
  }
 
  async validateRowsCsv(row: LocodeRow): Promise<void> {
    await validateValueAgainstSchema(row, locodeRowSchema)
  }
 
  async create(data: LocodeDto, options?: Options): Promise<Locode> {
    const { country_code, code } = data;
    const [dbCountry, { count: existing }] = await Promise.all([
      this.countryRepo.findOne({ where: { code: country_code } }, options),
      this.locodeRepo.count({ code }, options)
    ]);
    if (!dbCountry) {
      throw new HttpErrors.NotFound(`The country code not exists: ${country_code}`);
    }
 
    if (existing) {
      throw new HttpErrors.BadRequest(`The locode already exists: ${code}`);
    }
 
    return this.locodeRepo.create({ ...omit(data, ['country_code']), country_id: dbCountry.id }, options);
  }
 
  /**
   * Creates locode from csv files
   * @param [uploadedFiles]
   * @returns
   */
  async createLocodeFromCSV(uploadedFiles?: UploadFileType) {
    const csvParser = new CSVParser<LocodeRow>(this);
    const tx = await this.locodeRepo.beginTransaction(IsolationLevel.SERIALIZABLE);
    try {
      const results = await csvParser.createRecordsFromCSV(uploadedFiles, { transaction: tx })
      await tx.commit();
      return results;
    } catch (error) {
      await tx.rollback();
      throw new HttpErrors.BadRequest(error.message);
    }
  }
}