Skip to content

Commit

Permalink
feat: add shelter filter by geolocation radius (#93)
Browse files Browse the repository at this point in the history
  • Loading branch information
AndersonCRocha authored May 14, 2024
1 parent 9362f4c commit b24a7b7
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 3 deletions.
21 changes: 21 additions & 0 deletions src/shelter/ShelterSearch.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Prisma } from '@prisma/client';

import { calculateGeolocationBounds } from '@/utils/utils';
import { SupplyPriority } from 'src/supply/types';
import { PrismaService } from '../prisma/prisma.service';
import {
Expand Down Expand Up @@ -129,11 +130,31 @@ class ShelterSearch {
};
}

get geolocation(): Prisma.ShelterWhereInput {
if (!this.formProps.geolocation) return {};

const { minLat, maxLat, minLong, maxLong } = calculateGeolocationBounds(
this.formProps.geolocation,
);

return {
latitude: {
gte: minLat,
lte: maxLat,
},
longitude: {
gte: minLong,
lte: maxLong,
},
};
}

get query(): Prisma.ShelterWhereInput {
if (Object.keys(this.formProps).length === 0) return {};
const queryData = {
AND: [
this.cities,
this.geolocation,
{ OR: this.search },
{ OR: this.shelterStatus },
this.priority(this.formProps.supplyIds),
Expand Down
9 changes: 9 additions & 0 deletions src/shelter/types/search.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ export type ShelterTagType = z.infer<typeof ShelterTagTypeSchema>;

export type ShelterTagInfo = z.infer<typeof ShelterTagInfoSchema>;

export const GeolocationFilterSchema = z.object({
latitude: z.coerce.number(),
longitude: z.coerce.number(),
radiusInMeters: z.coerce.number(),
});

export type GeolocationFilter = z.infer<typeof GeolocationFilterSchema>;

export const ShelterSearchPropsSchema = z.object({
search: z.string().optional(),
priority: z.preprocess(
Expand All @@ -32,6 +40,7 @@ export const ShelterSearchPropsSchema = z.object({
shelterStatus: z.array(ShelterStatusSchema).optional(),
tags: ShelterTagInfoSchema.nullable().optional(),
cities: z.array(z.string()).optional(),
geolocation: GeolocationFilterSchema.optional(),
});

export type ShelterSearchProps = z.infer<typeof ShelterSearchPropsSchema>;
Expand Down
42 changes: 39 additions & 3 deletions src/utils/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Logger } from '@nestjs/common';
import { GeolocationFilter } from 'src/shelter/types/search.types';

class ServerResponse<T> {
readonly message: string;
Expand Down Expand Up @@ -75,10 +76,45 @@ function deepMerge(target: Record<string, any>, source: Record<string, any>) {
}
}

interface Coordinates {
maxLat: number;
minLat: number;
maxLong: number;
minLong: number;
}

function calculateGeolocationBounds({
latitude,
longitude,
radiusInMeters,
}: GeolocationFilter): Coordinates {
const earthRadius = 6371000;

const latRad = (latitude * Math.PI) / 180;

const radiusRad = radiusInMeters / earthRadius;

const maxLat = latitude + radiusRad * (180 / Math.PI);
const minLat = latitude - radiusRad * (180 / Math.PI);

const deltaLong = Math.asin(Math.sin(radiusRad) / Math.cos(latRad));

const maxLong = longitude + deltaLong * (180 / Math.PI);
const minLong = longitude - deltaLong * (180 / Math.PI);

return {
maxLat,
minLat,
maxLong,
minLong,
};
}

export {
ServerResponse,
removeNotNumbers,
getSessionData,
deepMerge,
calculateGeolocationBounds,
capitalize,
deepMerge,
getSessionData,
removeNotNumbers,
};

0 comments on commit b24a7b7

Please sign in to comment.