This commit is contained in:
2025-05-22 12:37:14 +05:00
parent ea830f0289
commit 0ec4ba5d18
5 changed files with 447 additions and 94 deletions
+61 -39
View File
@@ -1,43 +1,65 @@
// import { db } from "./src/db/index";
// import { IUnit } from "./src/types/IUnit";
// import { unitsTable } from "./src/db/schema/units";
// import got from "got";
import { db } from "./src/db/index";
import { IUnit } from "./src/types/IUnit";
import { unitsTable } from "./src/db/schema/units";
import got from "got";
// import { and, eq, exists } from "drizzle-orm";
// const { units } = await got
// .get(
// "https://irth-test-ii-16348121.dev.odoo.com/3d-fields/1?token=f82a4708-9a4d-491a-9424-1580b7173ba6"
// )
// .json<{ units: IUnit[] }>();
const { units: unitsOfMarasiDrive } = await got
.get(
"https://irth-test-ii-16348121.dev.odoo.com/3d-fields/1?token=f82a4708-9a4d-491a-9424-1580b7173ba6"
)
.json<{ units: IUnit[] }>();
// for (const {
// no_of_bathrooms,
// floor,
// no_of_parking_space,
// project,
// sales_price,
// square_ft,
// state,
// suits_area,
// unit_no,
// unit_type,
// unit_view,
// } of units) {
// type Unit = typeof unitsTable.$inferInsert;
const { units: unitsOfDubaiMarina } = await got
.get(
"https://irth-test-ii-16348121.dev.odoo.com/3d-fields/7?token=f82a4708-9a4d-491a-9424-1580b7173ba6"
)
.json<{ units: IUnit[] }>();
// const unit: Unit = {
// unitNo: unit_no,
// number: +unit_no.slice(2),
// project,
// floor: +floor,
// noOfBathrooms: no_of_bathrooms,
// noOfParkingSpace: no_of_parking_space,
// salesPrice: sales_price,
// state: state as Unit["state"],
// unitType: unit_type as Unit["unitType"],
// unitView: unit_view as Unit["unitView"],
// suitsArea: suits_area.toString(),
// squareFt: square_ft.toString(),
// };
for (const {
no_of_bathrooms,
floor,
no_of_parking_space,
project,
sales_price,
square_ft,
state,
suits_area,
unit_no,
unit_type,
unit_view,
balcony_area,
} of unitsOfMarasiDrive.concat(unitsOfDubaiMarina)) {
type Unit = typeof unitsTable.$inferInsert;
// await db.insert(unitsTable).values(unit);
// }
const parts = unit_no.split("-");
const unit: Unit = {
unitNo: unit_no,
number:
parts.length === 1
? +parts[0]
: !Number.isNaN(+parts[0])
? +parts[0]
: +parts[1],
project,
floor: +floor,
noOfBathrooms: no_of_bathrooms,
noOfParkingSpace: no_of_parking_space,
salesPrice: sales_price,
state: state as Unit["state"],
unitType: unit_type ? (unit_type as Unit["unitType"]) : null,
unitView: unit_view ? (unit_view as Unit["unitView"]) : null,
suitsArea: suits_area,
squareFt: square_ft,
balconyArea: balcony_area,
};
await db
.insert(unitsTable)
.values(unit)
.onConflictDoUpdate({
target: [unitsTable.project, unitsTable.unitNo],
set: unit,
});
}
+308 -5
View File
@@ -2,16 +2,63 @@ import Elysia, { error, t } from "elysia";
import { unitsTable } from "../db/schema";
import { createSelectSchema } from "drizzle-typebox";
import { db } from "../db";
import { eq, and } from "drizzle-orm";
import {
and,
asc,
between,
count,
desc,
eq,
inArray,
max,
min,
} from "drizzle-orm";
export const getUnitSchema = createSelectSchema(unitsTable);
export const unitsController = new Elysia({ prefix: "/units" }).get(
export const unitsController = new Elysia({ prefix: "/units" })
.get(
"/",
async ({ query: { project } }) => {
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),
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
),
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);
@@ -19,6 +66,262 @@ export const unitsController = new Elysia({ prefix: "/units" }).get(
}
},
{
query: t.Partial(t.Object({ project: t.String() })),
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
)
)
)[0].count;
} catch (err) {
console.log((err as Error).message);
return error(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 error(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"),
]),
})
),
}
);
+32 -9
View File
@@ -1,15 +1,29 @@
import { integer, pgTable, uuid, varchar, decimal } from "drizzle-orm/pg-core";
import { primaryKey } from "drizzle-orm/pg-core";
import { unique } from "drizzle-orm/pg-core";
import { doublePrecision } from "drizzle-orm/pg-core";
import { integer, pgTable, uuid, varchar } from "drizzle-orm/pg-core";
export const unitsTable = pgTable("units", {
export const unitsTable = pgTable(
"units",
{
id: uuid("id").defaultRandom().primaryKey(),
unitNo: varchar("unit_no", { length: 10 }).notNull(),
number: integer("number").notNull(),
number: integer("number"),
project: varchar("project", { length: 256 }).notNull(),
floor: integer("floor").notNull(),
unitType: varchar("unit_type", {
length: 256,
enum: ["Studio Squared", "1 BR Squared", "Studio Flex", "2 BR Squared"],
}).notNull(),
enum: [
"Studio Squared",
"1 BR Squared",
"Studio Flex",
"2 BR Squared",
"One Bedroom2",
"Studio2",
"One Bedroom Loft",
"Two Bedroom Loft",
],
}),
noOfBathrooms: integer("no_of_bathrooms").notNull(),
unitView: varchar("unit_view", {
length: 256,
@@ -24,14 +38,23 @@ export const unitsTable = pgTable("units", {
"BK/DT / Amenities",
"Corner-BK/DT / Amenities",
"Corner-Canal / BK/DT View",
"Marina View",
"Partial Marina View",
"Partial Marina, Partial City View",
"City view",
"Marina View, Sea View",
"Partial Marina View, Partial Sea View",
],
}).notNull(),
suitsArea: decimal("suits_area", { mode: "number" }).notNull(),
squareFt: decimal("square_ft", { mode: "number" }).notNull(),
}),
suitsArea: doublePrecision("suits_area").notNull(),
squareFt: doublePrecision("square_ft").notNull(),
noOfParkingSpace: integer("no_of_parking_space").notNull(),
salesPrice: integer("sales_price").notNull(),
state: varchar("state", {
length: 256,
enum: ["reserved", "sold_spa", "available", "sold_registered"],
}).notNull(),
});
balconyArea: doublePrecision("balcony_area").notNull(),
},
(t) => [unique().on(t.project, t.unitNo)]
);
+5 -1
View File
@@ -1,7 +1,11 @@
import { Elysia } from "elysia";
import { unitsController } from "./controllers/units";
import { cors } from "@elysiajs/cors";
const app = new Elysia().use(unitsController).listen(3000);
const app = new Elysia()
.use(cors({ origin: "*" }))
.use(unitsController)
.listen(3000);
console.log(
`🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`
+3 -2
View File
@@ -2,12 +2,13 @@ export interface IUnit {
unit_no: string;
project: string;
floor: string;
unit_type: string;
unit_type: string | false;
unit_view: string | false;
no_of_bathrooms: number;
unit_view: string;
suits_area: number;
square_ft: number;
no_of_parking_space: number;
sales_price: number;
state: string;
balcony_area: number;
}