Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/near me #173

Merged
merged 15 commits into from
Dec 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ FROM base as data
WORKDIR /app
COPY --from=install /app/node_modules ./node_modules
COPY . .
COPY ./src ./src
RUN sed -i 's/\r$//' ./setup.sh
RUN chmod +x ./setup.sh
RUN ./setup.sh

Expand All @@ -29,7 +29,8 @@ COPY --from=build /app/dist ./dist
COPY --from=build /app/package*.json ./
COPY --from=build /app/prisma ./prisma
COPY --from=data /app/db.mmdb ./db.mmdb
COPY --from=data /app/src ./src
COPY --from=data /app/src/geojson-data ./src/geojson-data
COPY ./src ./src
COPY tsconfig.json ./tsconfig.json
EXPOSE 3000

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"start:dev": "stencil start --watch",
"start:debug": "stencil start --debug --watch",
"start:prod": "NODE_ENV=production node dist/main",
"migrate:ingest:start:prod": "npx ts-node parse.geojson.ts && npx ts-node src/scripts/ingestors/state.geojson.ts && npx ts-node src/scripts/ingestors/district.geojson.ts && npx ts-node src/scripts/ingestors/subdistrict.geojson.ts && npm run migrate:start:prod",
"migrate:ingest:start:prod": "npx ts-node src/scripts/ingestors/state.geojson.ts && npx ts-node src/scripts/ingestors/district.geojson.ts && npx ts-node src/scripts/ingestors/subdistrict.geojson.ts && npm run migrate:start:prod",
"migrate:start:prod": "npx prisma migrate deploy && npm run start:prod",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
Expand Down
6 changes: 6 additions & 0 deletions prisma/migrations/alter_place/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- Enable PostGIS extension (if not already enabled)
CREATE EXTENSION IF NOT EXISTS postgis;

-- Alter the "location" column to use the geography type
ALTER TABLE "Place"
ALTER COLUMN "location" TYPE geography(Point, 4326) USING "location"::geography;
2 changes: 1 addition & 1 deletion prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,5 @@ model Place {
name String
type String
tag String
location Unsupported("geometry(Point, 4326)")
location Unsupported("geography(Point, 4326)")
}
10 changes: 8 additions & 2 deletions setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ else
# Update package list and install wget2 using apt
sudo apt update -y
sudo apt install wget2 -y
wget2 --help
else
echo "Unsupported OS detected."
exit 1
Expand Down Expand Up @@ -71,4 +70,11 @@ mv ./kl ./kerala
mv ./mh ./maharashtra
mv ./or ./odisha
mv ./rj ./rajasthan
mv ./sk ./sikkim
mv ./sk ./sikkim

# Changing PWD back to /src/
cd ../..

# Updating geoJSON files through script to make them usable in src
cd ./scripts
npx ts-node parse.geojson.ts
20 changes: 14 additions & 6 deletions src/modules/place/dto/place.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,27 @@ export class CreatePlaceDto {
}

export class SearchPlaceDto {
@ValidateIf((dto) => !dto.geofenceBoundary)
@IsArray()
@IsNotEmpty()
geofenceBoundary: number[][]; // Array of [lon, lat] pairs defining the geofence (polygon)

origin?: [number, number]; // [longitude, latitude]

@ValidateIf((dto) => !dto.geofenceBoundary)
@IsNumber()
distance?: number; // Distance in meters

@ValidateIf((dto) => !dto.origin || !dto.distance)
@IsArray()
geofenceBoundary?: number[][]; // Polygon boundary

@IsOptional()
@IsString()
name?: string;

@IsOptional()
@IsString()
tag?: string;

@IsOptional()
@IsString()
type?: string;
}
}
71 changes: 35 additions & 36 deletions src/modules/place/place.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { HttpException, HttpStatus, Injectable, Logger } from "@nestjs/common";
import { CreatePlaceDto, SearchPlaceDto } from "./dto/place.dto";
import { PrismaService } from "../prisma/prisma.service";
import { Prisma } from "@prisma/client";

@Injectable()
export class PlaceService {
Expand All @@ -10,51 +11,49 @@ export class PlaceService {

async createPlace(createPlaceDto: CreatePlaceDto): Promise<any> {
const { name, type, tag, lat, lon } = createPlaceDto;
const point = `ST_SetSRID(ST_MakePoint(${lon}, ${lat}), 4326)`;
this.logger.debug(`Adding place ${createPlaceDto}`)
try {
return this.prisma.$executeRawUnsafe(
`INSERT INTO "Place" (name, type, tag, location) VALUES ($1, $2, $3, ${point})`,
name,
type,
tag,
);
} catch (error) {
throw new HttpException('Error adding places', HttpStatus.INTERNAL_SERVER_ERROR);
}

const query = `
INSERT INTO "Place" (name, type, tag, location)
VALUES ($1, $2, $3, ST_SetSRID(ST_MakePoint($4, $5), 4326)::geography)
`;

this.logger.debug(`Adding place: ${JSON.stringify(createPlaceDto)}`);
return this.prisma.$executeRawUnsafe(query, name, type, tag, lon, lat);
}



async searchPlaces(searchPlaceDto: SearchPlaceDto): Promise<any> {
const { geofenceBoundary, name, tag, type } = searchPlaceDto;

// Create a polygon for the geofence
const polygon = `ST_MakePolygon(ST_GeomFromText('LINESTRING(${geofenceBoundary
.map((point) => point.join(' '))
.join(', ')}, ${geofenceBoundary[0].join(' ')})', 4326))`;

// Base query for filtering places
let query = `
async searchPlaces(searchPlaceDto: SearchPlaceDto): Promise<any> {
const { origin, distance, name, tag, type } = searchPlaceDto;

if (!origin || !distance) {
throw new Error('Origin and distance are required for radial searches.');
}

const [longitude, latitude] = origin;

// Construct the base query
let query = Prisma.sql`
SELECT id, name, type, tag, ST_AsText(location::geometry) as location
FROM "Place"
WHERE ST_Within(location, ${polygon})
WHERE ST_DWithin(location, ST_SetSRID(ST_MakePoint(${longitude}, ${latitude}), 4326)::geography, ${distance})
`;

// Add optional filters
// Add filters dynamically
if (name) {
query += ` AND name ILIKE '%${name}%'`;
query = Prisma.sql`${query} AND name ILIKE ${`%${name}%`}`;
}
else if (tag) {
query += ` AND tag ILIKE '%${tag}%'`;
if (tag) {
query = Prisma.sql`${query} AND tag ILIKE ${`%${tag}%`}`;
}
else if (type) {
query += ` AND type ILIKE '%${type}%'`;
}

try {
// Execute the query
return this.prisma.$queryRawUnsafe(query);
} catch (error) {
throw new HttpException('Error querying database', HttpStatus.INTERNAL_SERVER_ERROR);
if (type) {
query = Prisma.sql`${query} AND type ILIKE ${`%${type}%`}`;
}

this.logger.debug(`Executing search query: ${query.statement}`);
return this.prisma.$queryRaw(query);
}


}
Loading