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

404 Add new capital projects endpoint #410

Merged
merged 1 commit into from
Jan 31, 2025
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
2 changes: 2 additions & 0 deletions openapi/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ paths:
paths/boroughs_{boroughId}_community-districts_{communityDistrictId}_capital-projects_{z}_{x}_{y}.pbf.yaml
/capital-commitment-types:
$ref: paths/capital-commitment-types.yaml
/capital-projects:
$ref: paths/capital-projects.yaml
/capital-projects/{managingCode}/{capitalProjectId}/capital-commitments:
$ref: >-
paths/capital-projects_{managingCode}_{capitalProjectId}_capital-commitments.yaml
Expand Down
21 changes: 21 additions & 0 deletions openapi/paths/capital-projects.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
get:
summary: Find paginated capital projects.
operationId: findCapitalProjects
tags:
- Capital Projects
parameters:
- $ref: ../components/parameters/limitParam.yaml
- $ref: ../components/parameters/offsetParam.yaml
responses:
'200':
description: >-
An object containing pagination metadata and an array of capital
projects
content:
application/json:
schema:
$ref: ../components/schemas/CapitalProjectPage.yaml
'400':
$ref: ../components/responses/BadRequest.yaml
'500':
$ref: ../components/responses/InternalServerError.yaml
11 changes: 11 additions & 0 deletions src/capital-project/capital-project.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
Controller,
Get,
Param,
Query,
Res,
UseFilters,
UsePipes,
Expand All @@ -12,6 +13,7 @@ import {
FindCapitalProjectByManagingCodeCapitalProjectIdPathParams,
FindCapitalProjectGeoJsonByManagingCodeCapitalProjectIdPathParams,
FindCapitalProjectTilesPathParams,
FindCapitalProjectsQueryParams,
findCapitalCommitmentsByManagingCodeCapitalProjectIdPathParamsSchema,
findCapitalProjectByManagingCodeCapitalProjectIdPathParamsSchema,
findCapitalProjectGeoJsonByManagingCodeCapitalProjectIdPathParamsSchema,
Expand All @@ -24,6 +26,7 @@ import {
NotFoundExceptionFilter,
} from "src/filter";
import { ZodTransformPipe } from "src/pipes/zod-transform-pipe";
import { findCapitalProjectsQueryParamsSchema } from "src/gen/zod/findCapitalProjectsSchema";
@UseFilters(
BadRequestExceptionFilter,
InternalServerErrorExceptionFilter,
Expand All @@ -33,6 +36,14 @@ import { ZodTransformPipe } from "src/pipes/zod-transform-pipe";
export class CapitalProjectController {
constructor(private readonly capitalProjectService: CapitalProjectService) {}

@Get("/")
async findMany(
@Query(new ZodTransformPipe(findCapitalProjectsQueryParamsSchema))
queryParams: FindCapitalProjectsQueryParams,
) {
return await this.capitalProjectService.findMany(queryParams);
}

@UsePipes(
new ZodTransformPipe(
findCapitalProjectByManagingCodeCapitalProjectIdPathParamsSchema,
Expand Down
8 changes: 8 additions & 0 deletions src/capital-project/capital-project.repository.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ import {
import { mvtEntitySchema } from "src/schema/mvt";
import { z } from "zod";

export const findCapitalProjectsRepoSchema = z.array(
capitalProjectEntitySchema,
);

export type FindCapitalProjectsRepo = z.infer<
typeof findCapitalProjectsRepoSchema
>;

export const checkByManagingCodeCapitalProjectIdRepoSchema =
capitalProjectEntitySchema.pick({
id: true,
Expand Down
28 changes: 28 additions & 0 deletions src/capital-project/capital-project.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
FindByManagingCodeCapitalProjectIdRepo,
FindCapitalCommitmentsByManagingCodeCapitalProjectIdRepo,
FindGeoJsonByManagingCodeCapitalProjectIdRepo,
FindCapitalProjectsRepo,
FindTilesRepo,
} from "./capital-project.repository.schema";

Expand All @@ -30,6 +31,33 @@ export class CapitalProjectRepository {
private readonly db: DbType,
) {}

async findMany({
limit,
offset,
}: {
limit: number;
offset: number;
}): Promise<FindCapitalProjectsRepo> {
try {
return await this.db
.select({
id: capitalProject.id,
description: capitalProject.description,
managingCode: capitalProject.managingCode,
managingAgency: capitalProject.managingAgency,
maxDate: capitalProject.maxDate,
minDate: capitalProject.minDate,
category: sql<CapitalProjectCategory>`${capitalProject.category}`,
})
.from(capitalProject)
.limit(limit)
.offset(offset)
.orderBy(capitalProject.managingCode, capitalProject.id);
} catch {
throw new DataRetrievalException();
}
}

#checkByManagingCodeCapitalProjectId = this.db.query.capitalProject
.findFirst({
columns: {
Expand Down
18 changes: 18 additions & 0 deletions src/capital-project/capital-project.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
findCapitalProjectByManagingCodeCapitalProjectIdQueryResponseSchema,
findCapitalProjectGeoJsonByManagingCodeCapitalProjectIdQueryResponseSchema,
findCapitalProjectTilesQueryResponseSchema,
findCapitalProjectsQueryResponseSchema,
} from "src/gen";
import { ResourceNotFoundException } from "src/exception";

Expand All @@ -28,6 +29,23 @@ describe("CapitalProjectService", () => {
);
});

describe("findMany", () => {
it("should return a list of capital projects", async () => {
const capitalProjectsResponse = await capitalProjectService.findMany({});
expect(() =>
findCapitalProjectsQueryResponseSchema.parse(capitalProjectsResponse),
).not.toThrow();

const parsedBody = findCapitalProjectsQueryResponseSchema.parse(
capitalProjectsResponse,
);
expect(parsedBody.limit).toBe(20);
expect(parsedBody.offset).toBe(0);
expect(parsedBody.total).toBe(parsedBody.capitalProjects.length);
expect(parsedBody.order).toBe("managingCode, capitalProjectId");
});
});

describe("findByManagingCodeCapitalProjectId", () => {
it("should return a capital project with budget details", async () => {
const capitalProjectMock =
Expand Down
16 changes: 16 additions & 0 deletions src/capital-project/capital-project.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
FindCapitalProjectByManagingCodeCapitalProjectIdPathParams,
FindCapitalProjectGeoJsonByManagingCodeCapitalProjectIdPathParams,
FindCapitalProjectTilesPathParams,
FindCapitalProjectsQueryParams,
} from "src/gen";
import { CapitalProjectRepository } from "./capital-project.repository";
import { Inject } from "@nestjs/common";
Expand All @@ -19,6 +20,21 @@ export class CapitalProjectService {
private readonly capitalProjectRepository: CapitalProjectRepository,
) {}

async findMany({ limit = 20, offset = 0 }: FindCapitalProjectsQueryParams) {
const capitalProjects = await this.capitalProjectRepository.findMany({
limit,
offset,
});

return {
capitalProjects,
limit,
offset,
total: capitalProjects.length,
order: "managingCode, capitalProjectId",
};
}

async findByManagingCodeCapitalProjectId(
params: FindCapitalProjectByManagingCodeCapitalProjectIdPathParams,
) {
Expand Down
36 changes: 36 additions & 0 deletions src/gen/types/FindCapitalProjects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { CapitalProjectPage } from "./CapitalProjectPage";
import type { Error } from "./Error";

export type FindCapitalProjectsQueryParams = {
/**
* @description The maximum number of results to be returned in each response. The default value is 20. It must be between 1 and 100, inclusive.
* @type integer | undefined
*/
limit?: number;
/**
* @description The position in the full list to begin returning results. Default offset is 0. If the offset is beyond the end of the list, no results will be returned.
* @type integer | undefined
*/
offset?: number;
};
/**
* @description An object containing pagination metadata and an array of capital projects
*/
export type FindCapitalProjects200 = CapitalProjectPage;
/**
* @description Invalid client request
*/
export type FindCapitalProjects400 = Error;
/**
* @description Server side error
*/
export type FindCapitalProjects500 = Error;
/**
* @description An object containing pagination metadata and an array of capital projects
*/
export type FindCapitalProjectsQueryResponse = CapitalProjectPage;
export type FindCapitalProjectsQuery = {
Response: FindCapitalProjectsQueryResponse;
QueryParams: FindCapitalProjectsQueryParams;
Errors: FindCapitalProjects400 | FindCapitalProjects500;
};
1 change: 1 addition & 0 deletions src/gen/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export * from "./FindCapitalProjectGeoJsonByManagingCodeCapitalProjectId";
export * from "./FindCapitalProjectTiles";
export * from "./FindCapitalProjectTilesByBoroughIdCommunityDistrictId";
export * from "./FindCapitalProjectTilesByCityCouncilDistrictId";
export * from "./FindCapitalProjects";
export * from "./FindCapitalProjectsByBoroughIdCommunityDistrictId";
export * from "./FindCapitalProjectsByCityCouncilId";
export * from "./FindCityCouncilDistrictGeoJsonByCityCouncilDistrictId";
Expand Down
45 changes: 45 additions & 0 deletions src/gen/zod/findCapitalProjectsSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { z } from "zod";
import { capitalProjectPageSchema } from "./capitalProjectPageSchema";
import { errorSchema } from "./errorSchema";

export const findCapitalProjectsQueryParamsSchema = z
.object({
limit: z.coerce
.number()
.int()
.min(1)
.max(100)
.describe(
"The maximum number of results to be returned in each response. The default value is 20. It must be between 1 and 100, inclusive.",
)
.optional(),
offset: z.coerce
.number()
.int()
.min(0)
.describe(
"The position in the full list to begin returning results. Default offset is 0. If the offset is beyond the end of the list, no results will be returned.",
)
.optional(),
})
.optional();
/**
* @description An object containing pagination metadata and an array of capital projects
*/
export const findCapitalProjects200Schema = z.lazy(
() => capitalProjectPageSchema,
);
/**
* @description Invalid client request
*/
export const findCapitalProjects400Schema = z.lazy(() => errorSchema);
/**
* @description Server side error
*/
export const findCapitalProjects500Schema = z.lazy(() => errorSchema);
/**
* @description An object containing pagination metadata and an array of capital projects
*/
export const findCapitalProjectsQueryResponseSchema = z.lazy(
() => capitalProjectPageSchema,
);
1 change: 1 addition & 0 deletions src/gen/zod/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export * from "./findCapitalProjectTilesByCityCouncilDistrictIdSchema";
export * from "./findCapitalProjectTilesSchema";
export * from "./findCapitalProjectsByBoroughIdCommunityDistrictIdSchema";
export * from "./findCapitalProjectsByCityCouncilIdSchema";
export * from "./findCapitalProjectsSchema";
export * from "./findCityCouncilDistrictGeoJsonByCityCouncilDistrictIdSchema";
export * from "./findCityCouncilDistrictTilesSchema";
export * from "./findCityCouncilDistrictsSchema";
Expand Down
27 changes: 27 additions & 0 deletions src/gen/zod/operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ import {
findCapitalCommitmentTypes400Schema,
findCapitalCommitmentTypes500Schema,
} from "./findCapitalCommitmentTypesSchema";
import {
findCapitalProjectsQueryResponseSchema,
findCapitalProjects400Schema,
findCapitalProjects500Schema,
findCapitalProjectsQueryParamsSchema,
} from "./findCapitalProjectsSchema";
import {
findCapitalCommitmentsByManagingCodeCapitalProjectIdQueryResponseSchema,
findCapitalCommitmentsByManagingCodeCapitalProjectId400Schema,
Expand Down Expand Up @@ -336,6 +342,24 @@ export const operations = {
500: findCapitalCommitmentTypes500Schema,
},
},
findCapitalProjects: {
request: undefined,
parameters: {
path: undefined,
query: findCapitalProjectsQueryParamsSchema,
header: undefined,
},
responses: {
200: findCapitalProjectsQueryResponseSchema,
400: findCapitalProjects400Schema,
500: findCapitalProjects500Schema,
default: findCapitalProjectsQueryResponseSchema,
},
errors: {
400: findCapitalProjects400Schema,
500: findCapitalProjects500Schema,
},
},
findCapitalCommitmentsByManagingCodeCapitalProjectId: {
request: undefined,
parameters: {
Expand Down Expand Up @@ -774,6 +798,9 @@ export const paths = {
"/capital-commitment-types": {
get: operations["findCapitalCommitmentTypes"],
},
"/capital-projects": {
get: operations["findCapitalProjects"],
},
"/capital-projects/{managingCode}/{capitalProjectId}/capital-commitments": {
get: operations["findCapitalCommitmentsByManagingCodeCapitalProjectId"],
},
Expand Down
Loading