Skip to content

Commit

Permalink
feat: add create/search place APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
dhruv-1001 committed Dec 3, 2024
1 parent 920a911 commit 60597c2
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 4 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"supertest": "^6.3.3",
"ts-jest": "^29.1.0",
"ts-loader": "^9.4.3",
"ts-node": "^10.9.1",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.1.3"
},
Expand Down
10 changes: 10 additions & 0 deletions prisma/migrations/20241203015556_add_place/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- CreateTable
CREATE TABLE "Place" (
"id" SERIAL NOT NULL,
"name" TEXT NOT NULL,
"type" TEXT NOT NULL,
"tag" TEXT NOT NULL,
"location" geometry(Point, 4326) NOT NULL,

CONSTRAINT "Place_pkey" PRIMARY KEY ("id")
);
8 changes: 8 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,11 @@ model Village {
state_id Int?
state State? @relation(fields: [state_id], references: [state_code])
}

model Place {
id Int @id @default(autoincrement())
name String
type String
tag String
location Unsupported("geometry(Point, 4326)")
}
2 changes: 2 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import { ConfigModule } from '@nestjs/config';
import { config } from './config/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { PlaceModule } from './modules/place/place.module';

@Module({
imports: [
CityModule,
GeorevModule,
LocationModule,
PlaceModule,
PrismaModule,
ConfigModule.forRoot({
envFilePath: `.env`,
Expand Down
3 changes: 1 addition & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ async function bootstrap() {
const configService = app.get(ConfigService);
const port = configService.get<number>('port');
const host = configService.get<string>('host');
const method = configService.get<string>('method');

// Register plugins and middleware
await app.register(multipart);
Expand All @@ -46,7 +45,7 @@ async function bootstrap() {

// Start the server
await app.listen(port, host, (err, address) => {
logger.log(`Server running on ${method}://${host}:${port}`);
logger.log(`Server running on ${host}:${port}`);
});

// Log additional information as needed
Expand Down
36 changes: 36 additions & 0 deletions src/modules/place/dto/place.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { IsString, IsNumber, IsLatitude, IsLongitude, ValidateIf, IsNotEmpty, IsArray, IsOptional } from 'class-validator';

export class CreatePlaceDto {
@IsString()
name: string;

@IsString()
type: string;

@IsString()
tag: string;

@IsLatitude()
lat: number;

@IsLongitude()
lon: number;
}

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

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

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

@IsOptional()
@IsString()
type?: string;
}
20 changes: 20 additions & 0 deletions src/modules/place/place.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Body, Controller, Get, Post } from "@nestjs/common";
import { ApiTags } from "@nestjs/swagger";
import { PlaceService } from "./place.service";
import { CreatePlaceDto, SearchPlaceDto } from "./dto/place.dto";

@ApiTags('/place')
@Controller('place')
export class PlaceController {
constructor(private readonly placeService: PlaceService) {}

@Post('search')
async searchPlace(@Body() searchPlaceDto: SearchPlaceDto) {
return this.placeService.searchPlaces(searchPlaceDto);
}

@Post()
async addPlace(@Body() createPlaceDto: CreatePlaceDto) {
return this.placeService.createPlace(createPlaceDto);
}
}
9 changes: 9 additions & 0 deletions src/modules/place/place.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { PlaceController } from './place.controller';
import { PlaceService } from './place.service';

@Module({
controllers: [PlaceController],
providers: [PlaceService],
})
export class PlaceModule {}
52 changes: 52 additions & 0 deletions src/modules/place/place.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Injectable, Logger } from "@nestjs/common";
import { CreatePlaceDto, SearchPlaceDto } from "./dto/place.dto";
import { PrismaService } from "../prisma/prisma.service";

@Injectable()
export class PlaceService {
private readonly logger = new Logger(PlaceService.name);

constructor(private readonly prisma: PrismaService) { }

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}`)
return this.prisma.$executeRawUnsafe(
`INSERT INTO "Place" (name, type, tag, location) VALUES ($1, $2, $3, ${point})`,
name,
type,
tag,
);
}

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 = `
SELECT id, name, type, tag, ST_AsText(location::geometry) as location
FROM "Place"
WHERE ST_Within(location, ${polygon})
`;

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

// Execute the query
return this.prisma.$queryRawUnsafe(query);
}
}

0 comments on commit 60597c2

Please sign in to comment.