Skip to content
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
69 changes: 65 additions & 4 deletions src/adapters/property-base-adapter/generated/api-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,67 @@ export interface paths {
patch?: never;
trace?: never;
};
"/buildings/by-building-code/{buildingCode}": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Get detailed information about a specific building by building code
* @description Retrieves comprehensive information about a building using its building code.
* Returns details including construction year, renovation history, insurance information,
* and associated property data.
*
*/
get: {
parameters: {
query?: never;
header?: never;
path: {
/** @description The building code of the building */
buildingCode: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successfully retrieved building information */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
content?: components["schemas"]["Building"];
};
};
};
/** @description Building not found */
404: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Internal server error */
500: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/buildings/{id}": {
parameters: {
query?: never;
Expand Down Expand Up @@ -1214,11 +1275,11 @@ export interface components {
Building: {
id: string;
code: string;
name: string;
name: string | null;
buildingType: {
id: string;
code: string;
name: string;
id: string | null;
code: string | null;
name: string | null;
};
construction: {
constructionYear: number | null;
Expand Down
28 changes: 28 additions & 0 deletions src/adapters/property-base-adapter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,34 @@ export async function searchResidences(
}
}

type GetBuildingResponse = components['schemas']['Building']

export async function getBuildingByCode(
buildingCode: string
): Promise<AdapterResult<GetBuildingResponse, 'not-found' | 'unknown'>> {
try {
const fetchResponse = await client().GET(
'/buildings/by-building-code/{buildingCode}',
{
params: { path: { buildingCode } },
}
)

if (fetchResponse.data?.content) {
return { ok: true, data: fetchResponse.data.content }
}

if (fetchResponse.response.status === 404) {
return { ok: false, err: 'not-found' }
}

return { ok: false, err: 'unknown' }
} catch (err) {
logger.error({ err }, 'property-base-adapter.getBuilding')
return { ok: false, err: 'unknown' }
}
}

type GetCompaniesResponse = components['schemas']['Company'][]

export async function getCompanies(): Promise<
Expand Down
50 changes: 50 additions & 0 deletions src/adapters/tests/property-base-adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,56 @@
mockServer.close()
})

describe('getBuildingByCode', () => {
it('returns err if request fails', async () => {
mockServer.use(
http.get(
`${config.propertyBaseService.url}/buildings/by-building-code/123-123`,
() => new HttpResponse(null, { status: 500 })
)
)

const result = await propertyBaseAdapter.getBuildingByCode('123-123')
expect(result.ok).toBe(false)
if (!result.ok) expect(result.err).toBe('unknown')
})

it('returns not-found if building is not found', async () => {
mockServer.use(
http.get(
`${config.propertyBaseService.url}/buildings/by-building-code/123-123`,
() => new HttpResponse(null, { status: 404 })
)
)

const result = await propertyBaseAdapter.getBuildingByCode('123-123')
expect(result.ok).toBe(false)
if (!result.ok) expect(result.err).toBe('not-found')
})

it('returns building', async () => {
const buildingMock = factory.building.build()
mockServer.use(
http.get(
`${config.propertyBaseService.url}/buildings/by-building-code/123-123`,
() =>
HttpResponse.json(
{
content: buildingMock,
},
{ status: 200 }
)
)
)

const result = await propertyBaseAdapter.getBuildingByCode('123-123')
expect(result).toMatchObject({
ok: true,
data: buildingMock,
})
})
})

describe('getCompanies', () => {
it('returns err if request fails', async () => {
mockServer.use(
Expand Down Expand Up @@ -191,7 +241,7 @@

describe('getResidenceByRentalId', () => {
it('returns err if request fails', async () => {
const residenceDetailsMock = factory.residenceByRentalIdDetails.build()

Check warning on line 244 in src/adapters/tests/property-base-adapter.test.ts

View workflow job for this annotation

GitHub Actions / test

'residenceDetailsMock' is assigned a value but never used. Allowed unused vars must match /^_/u

mockServer.use(
http.get(
Expand Down
83 changes: 82 additions & 1 deletion src/services/property-base-service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { logger, generateRouteMetadata } from 'onecore-utilities'
import { registerSchema } from '../../utils/openapi'
import * as schemas from './schemas'
import { calculateResidenceStatus } from './calculate-residence-status'
import { z } from 'zod'

/**
* @swagger
Expand Down Expand Up @@ -37,6 +36,88 @@ export const routes = (router: KoaRouter) => {
schemas.ResidenceByRentalIdSchema
)

/**
* @swagger
* /propertyBase/buildings/by-building-code/{buildingCode}:
* get:
* summary: Get building by building code
* tags:
* - Property base Service
* description: Retrieves building data by building code
* parameters:
* - in: path
* name: buildingCode
* required: true
* schema:
* type: string
* description: The code of the building
* responses:
* '200':
* description: Successfully retrieved building
* content:
* application/json:
* schema:
* type: object
* properties:
* content:
* $ref: '#/components/schemas/Building'
* '404':
* description: Building not found
* content:
* application/json:
* schema:
* type: object
* properties:
* error:
* type: string
* example: Building not found
* '500':
* description: Internal server error
* content:
* application/json:
* schema:
* type: object
* properties:
* error:
* type: string
* example: Internal server error
* security:
* - bearerAuth: []
*/
router.get(
'(.*)/propertyBase/buildings/by-building-code/:buildingCode',
async (ctx) => {
const metadata = generateRouteMetadata(ctx)
const { buildingCode } = ctx.params

try {
const result = await propertyBaseAdapter.getBuildingByCode(buildingCode)

if (!result.ok) {
if (result.err === 'not-found') {
ctx.status = 404
ctx.body = { error: 'Building not found', ...metadata }
return
}

logger.error(result.err, 'Internal server error', metadata)
ctx.status = 500
ctx.body = { error: 'Internal server error', ...metadata }
return
}

ctx.body = {
content: result.data as schemas.Building,
...metadata,
}
} catch (error) {
logger.error(error, 'Internal server error', metadata)
ctx.status = 500
ctx.body = { error: 'Internal server error', ...metadata }
}
}
)

/**
* @swagger
* /propertyBase/companies:
Expand Down
26 changes: 26 additions & 0 deletions src/services/property-base-service/schemas.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
import { z } from 'zod'

export const BuildingSchema = z.object({
id: z.string(),
code: z.string(),
name: z.string(),
buildingType: z.object({
id: z.string(),
code: z.string(),
name: z.string(),
}),
construction: z.object({
constructionYear: z.number(),
renovationYear: z.number(),
valueYear: z.number().nullable(),
}),
features: z.object({
heating: z.string().nullable(),
fireRating: z.string().nullable(),
}),
insurance: z.object({
class: z.string().nullable(),
value: z.number().nullable(),
}),
deleted: z.boolean(),
})

export const CompanySchema = z.object({
id: z.string(),
propertyObjectId: z.string(),
Expand Down Expand Up @@ -322,6 +347,7 @@ export const StaircasesQueryParamsSchema = z.object({
.min(7, { message: 'buildingCode must be at least 7 characters long.' }),
})

export type Building = z.infer<typeof BuildingSchema>
export type Company = z.infer<typeof CompanySchema>
export type Property = z.infer<typeof PropertySchema>
export type PropertyDetails = z.infer<typeof PropertyDetailsSchema>
Expand Down
45 changes: 45 additions & 0 deletions src/services/property-base-service/tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,51 @@ app.use(router.routes())

beforeEach(jest.resetAllMocks)
describe('property-base-service', () => {
describe('GET /propertyBase/buildings/by-building-code/:buildingCode', () => {
it('returns 200 and a building by code', async () => {
const buildingMock = factory.building.build()
const getBuildingSpy = jest
.spyOn(propertyBaseAdapter, 'getBuildingByCode')
.mockResolvedValueOnce({ ok: true, data: buildingMock })

const res = await request(app.callback()).get(
`/propertyBase/buildings/by-building-code/${buildingMock.code}`
)

expect(res.status).toBe(200)
expect(getBuildingSpy).toHaveBeenCalledWith(buildingMock.code)
expect(JSON.stringify(res.body.content)).toEqual(
JSON.stringify(buildingMock)
)
})

it('returns 404 if no building is found', async () => {
const getBuildingSpy = jest
.spyOn(propertyBaseAdapter, 'getBuildingByCode')
.mockResolvedValueOnce({ ok: false, err: 'not-found' })

const res = await request(app.callback()).get(
'/propertyBase/buildings/by-building-code/123-456'
)

expect(res.status).toBe(404)
expect(getBuildingSpy).toHaveBeenCalledWith('123-456')
})

it('returns 500 if an error occurs', async () => {
const getBuildingSpy = jest
.spyOn(propertyBaseAdapter, 'getBuildingByCode')
.mockResolvedValueOnce({ ok: false, err: 'unknown' })

const res = await request(app.callback()).get(
'/propertyBase/buildings/by-building-code/123-456'
)

expect(res.status).toBe(500)
expect(getBuildingSpy).toHaveBeenCalledWith('123-456')
})
})

describe('GET /propertyBase/companies', () => {
it('returns 200 and a list of companies', async () => {
const companiesMock = factory.company.buildList(3)
Expand Down
2 changes: 1 addition & 1 deletion src/services/search-service/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const PropertySearchResultSchema = z.object({
export const BuildingSearchResultSchema = z.object({
id: z.string().describe('Unique identifier for the search result'),
type: z.literal('building').describe('Indicates this is a building result'),
name: z.string().describe('Name of the building'),
name: z.string().nullable().describe('Name of the building'),
property: z
.object({
name: z
Expand Down
Loading
Loading