Files
old-web/app/helpers/db/searchRequest.js

197 lines
4.5 KiB
JavaScript

"use strict";
const db = require("../../models/index");
const sequelize = require("sequelize");
const Op = sequelize.Op;
const { AD_CATEGORY } = require("../../common/enums");
const getSearchRequest = async searchRequestId => {
try {
return await db.SearchRequest.findByPk(searchRequestId);
} catch (error) {
console.log("searchrequest.js", error);
return null;
}
};
const createSearchRequest = async (searchRequestFields = {}) => {
return await db.SearchRequest.create(searchRequestFields);
};
const findSearchRequestsForRealEstate = async realEstate => {
const {
price,
area,
adType,
realEstateType,
locationLat,
locationLong,
accessRoadType,
balcony,
newBuilding,
elevator,
gardenSize,
numberOfRooms,
numberOfFloors,
floor
} = realEstate;
if (!locationLat || !locationLong) {
return [];
}
const stGeometry = sequelize.fn(
"ST_GEOMFROMTEXT",
`POINT (${locationLong} ${locationLat})`,
4326
);
const areaToSearchColumn = sequelize.col("areaToSearch");
const contains = sequelize.fn("ST_Contains", areaToSearchColumn, stGeometry);
const geoSearchQueryPart = sequelize.where(contains, true);
//General query contains only attributes that are defined for every RealEstate - not null
const query = {
adType,
realEstateType,
subscribed: true,
[Op.and]: geoSearchQueryPart
};
//Needed for defining which attribute should exist or not
const realEstateTypeObject = AD_CATEGORY[realEstateType];
//Needed to decide on including incomplete RealEstates data
let checkForIncompleteWanted = false;
//Attributes are checked separately and included in query only if defined - not null
//Price and area should be defined for every property
if (price != null) {
query.priceMin = {
[Op.lte]: price
};
query.priceMax = {
[Op.gte]: price
};
}
if (area != null) {
query.sizeMin = {
[Op.lte]: area
};
query.sizeMax = {
[Op.gte]: area
};
} else {
checkForIncompleteWanted = true;
}
//Other attributes can be defined or not depending on RealEstate type
//we check what to include in query based on real estate type object
if (realEstateTypeObject.hasGardenSize) {
if (gardenSize != null) {
query.gardenSizeMin = {
[Op.lte]: gardenSize
};
query.gardenSizeMax = {
[Op.gte]: gardenSize
};
} else {
checkForIncompleteWanted = true;
}
}
if (realEstateTypeObject.hasNumberOfRoom) {
if (numberOfRooms != null) {
query.numberOfRoomsMin = {
[Op.lte]: numberOfRooms
};
query.numberOfRoomsMax = {
[Op.gte]: numberOfRooms
};
} else {
checkForIncompleteWanted = true;
}
}
if (realEstateTypeObject.hasNumberOfFloors) {
if (numberOfFloors != null) {
query.numberOfFloorsMin = {
[Op.lte]: numberOfFloors
};
query.numberOfFloorsMax = {
[Op.gte]: numberOfFloors
};
} else {
checkForIncompleteWanted = true;
}
}
if (realEstateTypeObject.hasFloorProp) {
if (floor != null) {
query.floorMin = {
[Op.lte]: floor
};
query.floorMax = {
[Op.gte]: floor
};
} else {
checkForIncompleteWanted = true;
}
}
//AccessRoadType is defined - should exits for each ad and estate type
if (accessRoadType != null) {
query.accessRoadType = {
[Op.or]: {
[Op.eq]: "ANY",
[Op.eq]: accessRoadType
}
};
} else if (realEstateTypeObject.hasAccesRoadType) {
checkForIncompleteWanted = true;
}
if (realEstateTypeObject.hasBalconyProp) {
if (balcony != null) {
query.balcony = {
[Op.eq]: balcony
};
} else {
checkForIncompleteWanted = true;
}
}
if (realEstateTypeObject.hasNewBuildingProp) {
if (newBuilding != null) {
query.newBuilding = {
[Op.eq]: newBuilding
};
} else {
checkForIncompleteWanted = true;
}
}
if (realEstateTypeObject.hasElevatorProp) {
if (elevator != null) {
query.elevator = {
[Op.eq]: elevator
};
} else {
checkForIncompleteWanted = true;
}
}
//If one of the attributes that exists for property type is null
//we include in query to check if incomplete real estates are accepted
if (checkForIncompleteWanted) {
query.includeIncompleteAds = {
[Op.eq]: true
};
}
return await db.SearchRequest.findAll({ where: query });
};
module.exports = {
getSearchRequest,
createSearchRequest,
findSearchRequestsForRealEstate
};