UNPKG

@golemio/parkings

Version:
450 lines • 22.4 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ParkingRepository = void 0; const SourceEnum_1 = require("../../helpers/constants/SourceEnum"); const ParkingAverageOccupancyRepository_1 = require("./ParkingAverageOccupancyRepository"); const ParkingEntrancesRepository_1 = require("./ParkingEntrancesRepository"); const ParkingPaymentsRepository_1 = require("./ParkingPaymentsRepository"); const ParkingProhibitionsRepository_1 = require("./ParkingProhibitionsRepository"); const ParkingTariffRelationsRepository_1 = require("./ParkingTariffRelationsRepository"); const Di_1 = require("../ioc/Di"); const ModuleContainerToken_1 = require("../ioc/ModuleContainerToken"); const ParkingsLocationModel_1 = require("../models/ParkingsLocationModel"); const _sch_1 = require("../../schema-definitions"); const output_gateway_1 = require("@golemio/core/dist/output-gateway"); const golemio_errors_1 = require("@golemio/core/dist/shared/golemio-errors"); const sequelize_1 = require("@golemio/core/dist/shared/sequelize"); const tsyringe_1 = require("@golemio/core/dist/shared/tsyringe"); const ParkingOpeningHoursRepository_1 = require("./ParkingOpeningHoursRepository"); let ParkingRepository = exports.ParkingRepository = class ParkingRepository extends output_gateway_1.SequelizeModel { constructor(setup, locationModel, averageOccupancyRepository, parkingOpeningHoursRepository, entrancesRepository, paymentsRepository, parkingProhibitionsRepository, parkingTariffRelationsRepository) { super(setup.name, setup.tableName, setup.attributes, setup.options); this.locationModel = locationModel; this.averageOccupancyRepository = averageOccupancyRepository; this.parkingOpeningHoursRepository = parkingOpeningHoursRepository; this.entrancesRepository = entrancesRepository; this.paymentsRepository = paymentsRepository; this.parkingProhibitionsRepository = parkingProhibitionsRepository; this.parkingTariffRelationsRepository = parkingTariffRelationsRepository; this.shouldHideSecondarySourcesFromPrimaryData = true; this.groupBy = (array, key) => { if (!array || !Array.isArray(array)) { throw new Error("The input array must be a valid array."); } if (!key || typeof key !== "string") { throw new Error("The key must be a valid string."); } return array.reduce((map, item) => { if (!item || !item.hasOwnProperty(key)) { console.warn(`Item is missing the key "${key}":`, item); return map; } const groupKey = item[key]; if (!map.has(groupKey)) { map.set(groupKey, []); } map.get(groupKey).push(item); return map; }, new Map()); }; this.geoConfigHelper = Di_1.ParkingsContainer.resolve(ModuleContainerToken_1.ModuleContainerToken.GeoConfigHelper); this.associate(); } associate() { this.sequelizeModel.hasMany(this.locationModel.sequelizeModel, { as: "parking_locations", foreignKey: "source_id", sourceKey: "source_id", }); this.sequelizeModel.hasMany(this.entrancesRepository.sequelizeModel, { as: "parking_entrances", foreignKey: "parking_id", sourceKey: "id", }); this.sequelizeModel.hasOne(this.averageOccupancyRepository.sequelizeModel, { as: "parking_average_occupancy", foreignKey: "source_id", sourceKey: "source_id", }); this.sequelizeModel.hasMany(this.parkingOpeningHoursRepository.sequelizeModel, { as: "parking_hours", foreignKey: "parking_id", sourceKey: "id", }); this.sequelizeModel.hasOne(this.paymentsRepository.sequelizeModel, { as: "parking_payments", foreignKey: "parking_id", sourceKey: "id", }); this.sequelizeModel.hasOne(this.parkingProhibitionsRepository.sequelizeModel, { as: "parking_prohibitions", foreignKey: "parking_id", sourceKey: "id", }); this.sequelizeModel.hasOne(this.parkingTariffRelationsRepository.sequelizeModel, { as: "parking_tariffs_relation", foreignKey: "parking_id", sourceKey: "id", }); } async GetAll(params) { try { const { whereLocation, where, whereOpeningHours } = await this.prepareWhereConditions(params); const parkings = await this.sequelizeModel.findAll({ attributes: [ "id", "source", "source_id", "name", "valid_from", "centroid", "updated_at", "date_modified", "security", "max_vehicle_dimensions", "covered", "total_spot_number", "parking_policy", "contact", "category", "parking_type", "area", "address", "location", ], where, order: [["id", "ASC"]], limit: params.limit || 100, offset: params.offset || 0, bind: params.boundingBox && { lonMin: params.boundingBox[1], latMin: params.boundingBox[2], lonMax: params.boundingBox[3], latMax: params.boundingBox[0], }, raw: true, nest: true, }); if (parkings.length === 0) { return []; } const { parkingIds, sourceIds } = this.getUniqueParkingIds(parkings); const [parkingTariffsRelations, locations, openingHours, averageOccupancy, entrances, payments, prohibitions] = await Promise.all([ this.parkingTariffRelationsRepository.sequelizeModel.findAll({ attributes: ["parking_id", "tariff_id"], where: { parking_id: { [sequelize_1.Op.in]: Array.from(parkingIds) }, }, order: [["parking_id", "ASC"]], raw: true, }), this.locationModel.sequelizeModel.findAll({ attributes: ["id", "location", "address", "total_spot_number", "special_access", "source_id"], where: { source_id: { [sequelize_1.Op.in]: Array.from(sourceIds) }, ...whereLocation, }, order: [["id", "ASC"]], raw: true, }), this.parkingOpeningHoursRepository.sequelizeModel.findAll({ attributes: ["parking_id", "valid_from", "valid_to", "periods_of_time"], where: { parking_id: { [sequelize_1.Op.in]: Array.from(parkingIds) }, ...whereOpeningHours, }, order: [["valid_from", "ASC"]], raw: true, }), this.averageOccupancyRepository.sequelizeModel.findAll({ attributes: ["source_id", "day_of_week", "hour"], where: { source_id: { [sequelize_1.Op.in]: Array.from(sourceIds) }, }, order: [ ["day_of_week", "ASC"], ["hour", "ASC"], ], raw: true, }), this.entrancesRepository.sequelizeModel.findAll({ attributes: [ "parking_id", "entry", "exit", "entrance_type", "level", "max_height", "max_width", "max_length", "max_weight", "location", ], where: { parking_id: { [sequelize_1.Op.in]: Array.from(parkingIds) }, }, order: [["entrance_id", "ASC"]], raw: true, }), this.paymentsRepository.sequelizeModel.findAll({ attributes: [ "parking_id", "payment_web_url", "payment_android_url", "payment_ios_url", "payment_discovery_url", ], where: { parking_id: { [sequelize_1.Op.in]: Array.from(parkingIds) }, }, order: [["parking_id", "ASC"]], raw: true, }), this.parkingProhibitionsRepository.sequelizeModel.findAll({ attributes: ["parking_id", "lpg", "bus", "truck", "motorcycle", "bicycle", "trailer"], where: { parking_id: { [sequelize_1.Op.in]: Array.from(parkingIds) }, }, order: [["parking_id", "ASC"]], raw: true, }), ]); const averageOccupancyMap = new Map(averageOccupancy.map((ao) => [ao.source_id, ao])); const paymentsMap = new Map(payments.map((p) => [p.parking_id, p])); const parkingTariffsRelationsMap = new Map(parkingTariffsRelations.map((p) => [p.parking_id, p.tariff_id])); const prohibitionsMap = new Map(prohibitions.map((pr) => [pr.parking_id, pr])); const locationsMap = this.groupBy(locations, "source_id"); const openingHoursMap = this.groupBy(openingHours, "parking_id"); const entrancesMap = this.groupBy(entrances, "parking_id"); const filteredParkings = []; for (const parking of parkings) { if (!locationsMap.has(parking.source_id)) { continue; } parking.parking_locations = locationsMap.get(parking.source_id) || []; parking.parking_hours = openingHoursMap.get(parking.id) || []; parking.parking_entrances = entrancesMap.get(parking.id) || []; parking.parking_average_occupancy = averageOccupancyMap.get(parking.source_id) !== undefined; parking.parking_payments = paymentsMap.get(parking.id) || {}; parking.parking_prohibitions = prohibitionsMap.get(parking.id) || {}; parking.tariff_id = parkingTariffsRelationsMap.get(parking.id) || null; filteredParkings.push(parking); } return filteredParkings; } catch (err) { throw new golemio_errors_1.GeneralError("Database error ~ GetAll " + err.message, this.name, err, 500); } } async GetOne(id, sources) { try { if (!sources) { throw new golemio_errors_1.GeneralError("List of sources must be provided!", this.name, undefined, 500); } const result = await this.sequelizeModel.findOne({ attributes: { include: ["updated_at"] }, include: [ { model: this.parkingTariffRelationsRepository.sequelizeModel, as: "parking_tariffs_relation", attributes: ["tariff_id"], required: false, subQuery: false, }, { model: this.locationModel.sequelizeModel, as: "parking_locations", on: { source: { [sequelize_1.Op.eq]: sequelize_1.Sequelize.col(`"${this.sequelizeModel.tableName}".source`), }, source_id: { [sequelize_1.Op.eq]: sequelize_1.Sequelize.col(`"${this.sequelizeModel.tableName}".source_id`), }, }, required: true, subQuery: false, }, { model: this.parkingOpeningHoursRepository.sequelizeModel, as: "parking_hours", on: { parking_id: { [sequelize_1.Op.eq]: sequelize_1.Sequelize.col(`"${this.sequelizeModel.tableName}".id`), }, }, required: false, subQuery: false, }, { model: this.averageOccupancyRepository.sequelizeModel, as: "parking_average_occupancy", attributes: ["source_id"], on: { source: { [sequelize_1.Op.eq]: sequelize_1.Sequelize.col(`"${this.sequelizeModel.tableName}".source`), }, source_id: { [sequelize_1.Op.eq]: sequelize_1.Sequelize.col(`"${this.sequelizeModel.tableName}".source_id`), }, }, required: false, subQuery: false, }, { model: this.entrancesRepository.sequelizeModel, as: "parking_entrances", on: { parking_id: { [sequelize_1.Op.eq]: sequelize_1.Sequelize.col(`"${this.sequelizeModel.tableName}".id`), }, }, required: false, subQuery: false, }, { model: this.paymentsRepository.sequelizeModel, as: "parking_payments", required: false, subQuery: false, }, { model: this.parkingProhibitionsRepository.sequelizeModel, as: "parking_prohibitions", attributes: ["lpg", "bus", "truck", "motorcycle", "bicycle", "trailer"], required: false, subQuery: false, }, ], where: { id, source: { [sequelize_1.Op.in]: sources, }, }, order: [ [{ model: this.locationModel.sequelizeModel, as: "parking_locations" }, "id", "ASC"], [{ model: this.parkingOpeningHoursRepository.sequelizeModel, as: "parking_hours" }, "valid_from", "ASC"], [ { model: this.averageOccupancyRepository.sequelizeModel, as: "parking_average_occupancy" }, "day_of_week", "ASC", ], [{ model: this.averageOccupancyRepository.sequelizeModel, as: "parking_average_occupancy" }, "hour", "ASC"], [{ model: this.entrancesRepository.sequelizeModel, as: "parking_entrances" }, "entrance_id", "ASC"], ], }); if (result === null) { return null; } const resultData = result.dataValues; resultData.parking_locations = resultData.parking_locations.map((location) => location.dataValues); resultData.parking_hours = resultData.parking_hours.map((item) => item.dataValues); resultData.parking_average_occupancy = !!resultData.parking_average_occupancy; return resultData; } catch (err) { throw new golemio_errors_1.GeneralError("Database error ~ GetOne " + err.message, this.name, err, 500); } } async prepareWhereConditions(params) { let where = {}; let whereLocation = {}; let whereOpeningHours = {}; let primarySources = []; const areaLimit = sequelize_1.Sequelize.fn("ST_BuildArea", sequelize_1.Sequelize.fn("ST_GeomFromGeoJSON", JSON.stringify(this.geoConfigHelper.returnGeoCoordinates()))); if (params.primarySource) { primarySources = params.primarySource; } else { throw new golemio_errors_1.GeneralError("List of sources must be provided! ", this.name, undefined, 500); } // DO NOT SHOW OSM PARKINGS IF THERE ARE OTHER SOURCES if (this.shouldHideSecondarySourcesFromPrimaryData && primarySources.length > 1) { primarySources = primarySources.filter((source) => source !== SourceEnum_1.SourceEnum.OSM); } where.source = { [sequelize_1.Op.in]: primarySources }; where.location = sequelize_1.Sequelize.where(sequelize_1.Sequelize.fn("ST_Within", sequelize_1.Sequelize.col("sanitized_location"), areaLimit), "true"); if (params.validFrom) { where.valid_from = { [sequelize_1.Op.gte]: params.validFrom }; } if (params.minutesBefore) { where.updated_at = { [sequelize_1.Op.gte]: sequelize_1.Sequelize.literal(`NOW() - INTERVAL '${params.minutesBefore} minutes'`) }; } if (params.updatedSince) { where.updated_at = { [sequelize_1.Op.gte]: params.updatedSince }; } if (params.parkingPolicy) { where.parking_policy = { [sequelize_1.Op.in]: params.parkingPolicy }; } if (params.activeOnly === true) { where.active = true; } if (params.boundingBox) { where = { ...where, [sequelize_1.Op.and]: (0, sequelize_1.literal)(`ST_Contains(ST_MakeEnvelope($lonMin, $latMin, $lonMax, $latMax, 4326), location)`), }; } if (params.accessDedicatedTo) { whereLocation.special_access = { [sequelize_1.Op.overlap]: params.accessDedicatedTo }; } if (params.openTo) { whereOpeningHours.valid_from = { [sequelize_1.Op.lte]: params.openTo }; } if (params.openFrom) { whereOpeningHours.valid_to = { [sequelize_1.Op.or]: [{ [sequelize_1.Op.gte]: params.openFrom }, { [sequelize_1.Op.eq]: null }], }; } return { whereLocation, where, whereOpeningHours }; } getUniqueParkingIds(parkings) { const parkingIds = new Set(); const sourceIds = new Set(); for (const parking of parkings) { if (parking.id) parkingIds.add(parking.id); if (parking.source_id) sourceIds.add(parking.source_id); } return { parkingIds, sourceIds }; } }; ParkingRepository.defaultSetup = { name: "OGParkingRepository", tableName: _sch_1.Parkings.parkings.pgTableName, attributes: _sch_1.Parkings.parkings.outputSequelizeAttributes, options: { schema: _sch_1.Parkings.pgSchema }, }; exports.ParkingRepository = ParkingRepository = __decorate([ (0, tsyringe_1.injectable)(), __param(0, (0, tsyringe_1.inject)(ModuleContainerToken_1.ModuleContainerToken.ParkingRepositorySetup)), __param(1, (0, tsyringe_1.inject)(ModuleContainerToken_1.ModuleContainerToken.ParkingsLocationModel)), __param(2, (0, tsyringe_1.inject)(ModuleContainerToken_1.ModuleContainerToken.ParkingAverageOccupancyRepository)), __param(3, (0, tsyringe_1.inject)(ModuleContainerToken_1.ModuleContainerToken.ParkingOpeningHoursRepository)), __param(4, (0, tsyringe_1.inject)(ModuleContainerToken_1.ModuleContainerToken.ParkingEntrancesRepository)), __param(5, (0, tsyringe_1.inject)(ModuleContainerToken_1.ModuleContainerToken.ParkingPaymentsRepository)), __param(6, (0, tsyringe_1.inject)(ModuleContainerToken_1.ModuleContainerToken.ParkingProhibitionsRepository)), __param(7, (0, tsyringe_1.inject)(ModuleContainerToken_1.ModuleContainerToken.ParkingTariffRelationsRepository)), __metadata("design:paramtypes", [Object, ParkingsLocationModel_1.ParkingsLocationModel, ParkingAverageOccupancyRepository_1.ParkingAverageOccupancyRepository, ParkingOpeningHoursRepository_1.ParkingOpeningHoursRepository, ParkingEntrancesRepository_1.ParkingEntrancesRepository, ParkingPaymentsRepository_1.ParkingPaymentsRepository, ParkingProhibitionsRepository_1.ParkingProhibitionsRepository, ParkingTariffRelationsRepository_1.ParkingTariffRelationsRepository]) ], ParkingRepository); //# sourceMappingURL=ParkingRepository.js.map