"use strict"; const db = require("../../models/index"); const sequelize = require("sequelize"); const Op = sequelize.Op; const bulkUpsertRealEstates = async realEstateData => { try { const fieldsToUpdateIfDuplicate = [ "realEstateType", "adType", "price", "area", "streetNumber", "streetName", "locality", "municipality", "city", "region", "entity", "country", "locationLat", "locationLong", "title", "shortDescription", "longDescription", "gardenSize", "adStatus", "updatedAt", "renewedDate", "numberOfRooms", "numberOfFloors", "floor", "accessRoadType", "heatingType", "furnishingType", "balcony", "newBuilding", "elevator", "water", "electricity", "drainageSystem", "registeredInZkBooks", "recentlyAdapted", "parking", "garage", "gas", "antiTheftDoor", "airCondition", "phoneConnection", "cableTV", "internet", "basementAttic", "storeRoom", "videoSurveillance", "alarm", "suitableForStudents", "includingBills", "animalsAllowed", "pool", "urbanPlanPermit", "buildingPermit", "utilityConnection", "distanceToRiver", "numberOfViewsAgency" ]; const order = [["updatedAt", "desc"]]; return await db.RealEstate.bulkCreate(realEstateData, { updateOnDuplicate: fieldsToUpdateIfDuplicate, returning: true, order }); } catch (e) { console.log("Error bulk upserting realEstates : ", e); } }; const getRealEstateById = async id => { return db.RealEstate.findByPk(id); }; const findRealEstatesForSearchRequest = async (searchRequest, maxResults) => { const { priceMin, priceMax, sizeMin, sizeMax, adType, realEstateType, areaToSearch, gardenSizeMin, gardenSizeMax, numberOfRoomsMin, numberOfRoomsMax, numberOfFloorsMin, numberOfFloorsMax, floorMin, floorMax, includeIncompleteAds, balcony, elevator, newBuilding, accessRoadType } = searchRequest; const longitudeColumn = sequelize.col("locationLong"); const latitudeColumn = sequelize.col("locationLat"); const pointGeometry = sequelize.fn( "ST_Point", longitudeColumn, latitudeColumn ); const pointWithSRID = sequelize.fn("ST_SetSRID", pointGeometry, 4326); const areaToSearchAsGeometry = sequelize.fn( "ST_GeomFromGeoJSON", JSON.stringify(areaToSearch) ); const areaToSearchWithSRID = sequelize.fn( "ST_SetSRID", areaToSearchAsGeometry, 4326 ); const contains = sequelize.fn( "ST_Contains", areaToSearchWithSRID, pointWithSRID ); const geoSearchQueryPart = sequelize.where(contains, true); //General queries contain only attributes that are defined for every searchreq //Query for case of complete ads const query = { adType, realEstateType, price: { [Op.lte]: priceMax, [Op.gte]: priceMin }, area: { [Op.lte]: sizeMax, [Op.gte]: sizeMin }, accessRoadType: { [Op.or]: { [Op.eq]: 'ANY', [Op.eq]: accessRoadType } }, [Op.and]: geoSearchQueryPart } //Query for case of incomplete ads const queryIncludeIncomplete = { adType, realEstateType, price: { [Op.or] : { [Op.and] : { [Op.lte]: priceMax, [Op.gte]: priceMin }, [Op.is] : null } }, area: { [Op.or] : { [Op.and]: { [Op.lte]: sizeMax, [Op.gte]: sizeMin }, [Op.is]: null } }, accessRoadType: { [Op.or]: { [Op.eq]: 'ANY', [Op.eq]: accessRoadType, [Op.is]: null } }, [Op.and]: geoSearchQueryPart } //Every other attribute is checked separately and included in query only if it is defined if (gardenSizeMax && gardenSizeMin) { query.gardenSize = { [Op.lte]: gardenSizeMax, [Op.gte]: gardenSizeMin } queryIncludeIncomplete.gardenSize = { [Op.or] : { [Op.and]: { [Op.lte]: gardenSizeMax, [Op.gte]: gardenSizeMin }, [Op.is]: null } } } if (numberOfRoomsMin && numberOfRoomsMax) { query.numberOfRooms = { [Op.lte]: numberOfRoomsMax, [Op.gte]: numberOfRoomsMin } queryIncludeIncomplete.numberOfRooms = { [Op.or] : { [Op.and]: { [Op.lte]: numberOfRoomsMax, [Op.gte]: numberOfRoomsMin }, [Op.is]: null } } } if (numberOfFloorsMin && numberOfFloorsMax) { query.numberOfFloors = { [Op.lte]: numberOfFloorsMax, [Op.gte]: numberOfFloorsMin } queryIncludeIncomplete.numberOfFloors = { [Op.or] : { [Op.and]: { [Op.lte]: numberOfFloorsMax, [Op.gte]: numberOfFloorsMin }, [Op.is]: null } } } if (floorMin && floorMax) { query.floor = { [Op.lte]: floorMax, [Op.gte]: floorMin } queryIncludeIncomplete.floor = { [Op.or] : { [Op.and]: { [Op.lte]: floorMax, [Op.gte]: floorMin }, [Op.is]: null } } } if (balcony) { query.balcony = { [Op.eq]: balcony } queryIncludeIncomplete.balcony = { [Op.or]: { [Op.eq]: balcony, [Op.is]: null } } } if (newBuilding) { query.newBuilding = { [Op.eq]: newBuilding } queryIncludeIncomplete.newBuilding = { [Op.or]: { [Op.eq]: newBuilding, [Op.is]: null } } } if (elevator) { query.elevator = { [Op.eq]: elevator } queryIncludeIncomplete.elevator = { [Op.or]: { [Op.eq]: elevator, [Op.is]: null } } } const order = [["updatedAt", "desc"]]; if(!includeIncompleteAds) { return await db.RealEstate.findAll({ where: query, limit: maxResults, order }); } else { return await db.RealEstate.findAll({ where: queryIncludeIncomplete, limit: maxResults, order }); } }; module.exports = { bulkUpsertRealEstates, getRealEstateById, findRealEstatesForSearchRequest };