Files
irth-backend/src/controllers/units.ts
T
2025-05-27 13:03:07 +05:00

417 lines
13 KiB
TypeScript

import Elysia, { status, t } from "elysia";
import { unitsTable } from "../db/schema";
import { createSelectSchema } from "drizzle-typebox";
import { db } from "../db";
import {
and,
asc,
between,
count,
desc,
eq,
inArray,
max,
min,
isNull,
not,
} from "drizzle-orm";
export const getUnitSchema = createSelectSchema(unitsTable);
export const unitsController = new Elysia({ prefix: "/units" })
.get(
"/",
async ({
query: {
project,
unitTypes,
cost,
floor,
area,
view,
order,
offset,
limit,
},
}) => {
try {
return await db.query.unitsTable.findMany({
where: and(
project ? eq(unitsTable.project, project) : undefined,
unitTypes ? inArray(unitsTable.unitType, unitTypes) : undefined,
cost ? between(unitsTable.salesPrice, cost[0], cost[1]) : undefined,
floor ? between(unitsTable.floor, floor[0], floor[1]) : undefined,
area ? between(unitsTable.squareFt, area[0], area[1]) : undefined,
view ? eq(unitsTable.unitView, view) : undefined,
not(isNull(unitsTable.unitType))
),
orderBy: order
? [
order[1] === "asc"
? asc(
unitsTable[
order[0] === "cost" ? "salesPrice" : "squareFt"
]
)
: desc(
unitsTable[
order[0] === "cost" ? "salesPrice" : "squareFt"
]
),
]
: undefined,
offset,
limit,
});
} catch (err) {
console.log((err as Error).message);
return status(500, "Internal server error");
}
},
{
query: t.Partial(
t.Object({
project: t.String(),
unitTypes: t.Array(
t.Union([
t.Literal("Studio Squared"),
t.Literal("1 BR Squared"),
t.Literal("Studio Flex"),
t.Literal("2 BR Squared"),
t.Literal("Studio2"),
t.Literal("One Bedroom2"),
t.Literal("One Bedroom Loft"),
t.Literal("Two Bedroom Loft"),
])
),
cost: t.Tuple([t.Number(), t.Number()]),
floor: t.Tuple([t.Number(), t.Number()]),
area: t.Tuple([t.Number(), t.Number()]),
view: t.Union([
t.Literal("Canal / Amenities"),
t.Literal("Corner-Canal / Amenities"),
t.Literal("Corner-Canal View"),
t.Literal("Business Bay"),
t.Literal("Park Facing"),
t.Literal("Corner-Park Facing"),
t.Literal("Partial Park"),
t.Literal("BK/DT / Amenities"),
t.Literal("Corner-BK/DT / Amenities"),
t.Literal("Corner-Canal / BK/DT View"),
t.Literal("Marina View"),
t.Literal("Partial Marina View"),
t.Literal("Partial Marina, Partial City View"),
t.Literal("City view"),
t.Literal("Marina View, Sea View"),
t.Literal("Partial Marina View, Partial Sea View"),
]),
order: t.Tuple([
t.Union([t.Literal("cost"), t.Literal("sqft")]),
t.Union([t.Literal("asc"), t.Literal("desc")]),
]),
offset: t.Number({ default: 0 }),
limit: t.Number({ default: 16 }),
})
),
}
)
.get(
"/count",
async ({ query: { project, unitTypes, cost, floor, area, view } }) => {
try {
return (
await db
.select({ count: count() })
.from(unitsTable)
.where(
and(
project ? eq(unitsTable.project, project) : undefined,
unitTypes ? inArray(unitsTable.unitType, unitTypes) : undefined,
cost
? between(unitsTable.salesPrice, cost[0], cost[1])
: undefined,
floor
? between(unitsTable.floor, floor[0], floor[1])
: undefined,
area
? between(unitsTable.squareFt, area[0], area[1])
: undefined,
view ? eq(unitsTable.unitView, view) : undefined,
not(isNull(unitsTable.unitType))
)
)
)[0].count;
} catch (err) {
console.log((err as Error).message);
return status(500, "Internal server error");
}
},
{
query: t.Partial(
t.Object({
project: t.String(),
unitTypes: t.Array(
t.Union([
t.Literal("Studio Squared"),
t.Literal("1 BR Squared"),
t.Literal("Studio Flex"),
t.Literal("2 BR Squared"),
t.Literal("Studio2"),
t.Literal("One Bedroom2"),
t.Literal("One Bedroom Loft"),
t.Literal("Two Bedroom Loft"),
])
),
cost: t.Tuple([t.Number(), t.Number()]),
floor: t.Tuple([t.Number(), t.Number()]),
area: t.Tuple([t.Number(), t.Number()]),
view: t.Union([
t.Literal("Canal / Amenities"),
t.Literal("Corner-Canal / Amenities"),
t.Literal("Corner-Canal View"),
t.Literal("Business Bay"),
t.Literal("Park Facing"),
t.Literal("Corner-Park Facing"),
t.Literal("Partial Park"),
t.Literal("BK/DT / Amenities"),
t.Literal("Corner-BK/DT / Amenities"),
t.Literal("Corner-Canal / BK/DT View"),
t.Literal("Marina View"),
t.Literal("Partial Marina View"),
t.Literal("Partial Marina, Partial City View"),
t.Literal("City view"),
t.Literal("Marina View, Sea View"),
t.Literal("Partial Marina View, Partial Sea View"),
]),
})
),
}
)
.get(
"/filters/:filterName",
async ({
query: { project, view, unitTypes, cost, floor, area },
params: { filterName },
}) => {
try {
const filters = and(
project ? eq(unitsTable.project, project) : undefined,
unitTypes && filterName !== "unitTypes"
? inArray(unitsTable.unitType, unitTypes)
: undefined,
view && filterName !== "views"
? eq(unitsTable.unitView, view)
: undefined,
cost && filterName !== "cost"
? between(unitsTable.salesPrice, cost[0], cost[1])
: undefined,
floor && filterName !== "floor"
? between(unitsTable.floor, floor[0], floor[1])
: undefined,
area && filterName !== "area"
? between(unitsTable.squareFt, area[0], area[1])
: undefined
);
if (filterName === "unitTypes")
return (
await db
.selectDistinctOn([unitsTable.unitType], {
unitType: unitsTable.unitType,
})
.from(unitsTable)
.where(filters)
)
.map((unit) => unit.unitType)
.filter(Boolean);
else if (filterName === "views")
return (
await db
.selectDistinctOn([unitsTable.unitView], {
unitView: unitsTable.unitView,
})
.from(unitsTable)
.where(filters)
)
.map((unit) => unit.unitView)
.filter(Boolean);
else if (filterName === "cost")
return (
await db
.select({
min: min(unitsTable.salesPrice),
max: max(unitsTable.salesPrice),
})
.from(unitsTable)
.where(filters)
)[0];
else if (filterName === "area")
return (
await db
.select({
min: min(unitsTable.squareFt),
max: max(unitsTable.squareFt),
})
.from(unitsTable)
.where(filters)
)[0];
return (
await db
.select({
min: min(unitsTable.floor),
max: max(unitsTable.floor),
})
.from(unitsTable)
.where(filters)
)[0];
} catch (err) {
console.log((err as Error).message);
return status(500, "Internal server error");
}
},
{
response: {
200: t.Union([
t.Array(t.String()),
t.Object({
min: t.Number(),
max: t.Number(),
}),
]),
500: t.ObjectString({}),
},
params: t.Object({
filterName: t.Union([
t.Literal("unitTypes"),
t.Literal("views"),
t.Literal("cost"),
t.Literal("area"),
t.Literal("floor"),
]),
}),
query: t.Partial(
t.Object({
project: t.String(),
unitTypes: t.Array(
t.Union([
t.Literal("Studio Squared"),
t.Literal("1 BR Squared"),
t.Literal("Studio Flex"),
t.Literal("2 BR Squared"),
t.Literal("Studio2"),
t.Literal("One Bedroom2"),
t.Literal("One Bedroom Loft"),
t.Literal("Two Bedroom Loft"),
])
),
cost: t.Tuple([t.Number(), t.Number()]),
floor: t.Tuple([t.Number(), t.Number()]),
area: t.Tuple([t.Number(), t.Number()]),
view: t.Union([
t.Literal("Canal / Amenities"),
t.Literal("Corner-Canal / Amenities"),
t.Literal("Corner-Canal View"),
t.Literal("Business Bay"),
t.Literal("Park Facing"),
t.Literal("Corner-Park Facing"),
t.Literal("Partial Park"),
t.Literal("BK/DT / Amenities"),
t.Literal("Corner-BK/DT / Amenities"),
t.Literal("Corner-Canal / BK/DT View"),
t.Literal("Marina View"),
t.Literal("Partial Marina View"),
t.Literal("Partial Marina, Partial City View"),
t.Literal("City view"),
t.Literal("Marina View, Sea View"),
t.Literal("Partial Marina View, Partial Sea View"),
]),
})
),
}
)
.get(
"/get-floors-data/:project",
async ({ params: { project } }) => {
try {
// Получаем данные о номерах квартир, этажах и типах
const unitsData = await db
.select()
.from(unitsTable)
.where(eq(unitsTable.project, decodeURIComponent(project)));
// Создаем структуру для хранения данных по этажам
const floorMap = new Map<
string | number,
{
floor: number;
East: {
types: Record<string, number>;
totalUnits: number;
};
West: {
types: Record<string, number>;
totalUnits: number;
};
others: {
types: Record<string, number>;
totalUnits: number;
};
}
>();
// Обрабатываем данные квартир
for (const unit of unitsData) {
if (unit.unitNo && unit.floor && unit.unitType) {
// Инициализируем данные для этажа, если их еще нет
// Инициализируем данные для этажа, если их еще нет
if (!floorMap.has(unit.floor)) {
floorMap.set(unit.floor, {
floor: unit.floor,
East: {
types: {},
totalUnits: 0,
},
West: {
types: {},
totalUnits: 0,
},
others: {
types: {},
totalUnits: 0,
},
});
}
const floorData = floorMap.get(unit.floor)!;
// Увеличиваем счетчик для типа квартиры на соответствующей стороне
if (unit.wing === "East") {
floorData.East.types[unit.unitType] =
(floorData.East.types[unit.unitType] || 0) + 1;
floorData.East.totalUnits++;
} else if (unit.wing === "West") {
floorData.West.types[unit.unitType] =
(floorData.West.types[unit.unitType] || 0) + 1;
floorData.West.totalUnits++;
} else {
floorData.others.types[unit.unitType] =
(floorData.others.types[unit.unitType] || 0) + 1;
floorData.others.totalUnits++;
}
}
}
// Преобразуем Map в массив и сортируем по этажам
return Array.from(floorMap.values()).sort((a, b) => a.floor - b.floor);
} catch (err) {
console.log((err as Error).message);
return status(500, "Internal server error");
}
},
{
params: t.Object({
project: t.String(),
}),
}
);