Compare commits
2 Commits
c389dcf95f
...
46002a2479
Author | SHA1 | Date | |
---|---|---|---|
46002a2479 | |||
dc6c1d680f |
4
.env.example
Normal file
4
.env.example
Normal file
@ -0,0 +1,4 @@
|
||||
DB_HOST=localhost
|
||||
DB_USER=root
|
||||
DB_PASSWORD=password
|
||||
DB_NAME=mysql
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -25,6 +25,7 @@ yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
|
32
bun.lock
32
bun.lock
@ -5,8 +5,10 @@
|
||||
"name": "pemweb-api",
|
||||
"dependencies": {
|
||||
"elysia": "latest",
|
||||
"mysql2": "^3.14.1",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.15.29",
|
||||
"bun-types": "latest",
|
||||
},
|
||||
},
|
||||
@ -18,7 +20,9 @@
|
||||
|
||||
"@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="],
|
||||
|
||||
"@types/node": ["@types/node@22.15.21", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ=="],
|
||||
"@types/node": ["@types/node@22.15.29", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ=="],
|
||||
|
||||
"aws-ssl-profiles": ["aws-ssl-profiles@1.1.2", "", {}, "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g=="],
|
||||
|
||||
"bun-types": ["bun-types@1.2.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-Kuh4Ub28ucMRWeiUUWMHsT9Wcbr4H3kLIO72RZZElSDxSu7vpetRvxIUDUaW6QtaIeixIpm7OXtNnZPf82EzwA=="],
|
||||
|
||||
@ -26,6 +30,8 @@
|
||||
|
||||
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
|
||||
|
||||
"denque": ["denque@2.1.0", "", {}, "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="],
|
||||
|
||||
"elysia": ["elysia@1.3.1", "", { "dependencies": { "cookie": "^1.0.2", "exact-mirror": "0.1.2", "fast-decode-uri-component": "^1.0.1" }, "optionalDependencies": { "@sinclair/typebox": "^0.34.33", "openapi-types": "^12.1.3" }, "peerDependencies": { "file-type": ">= 20.0.0", "typescript": ">= 5.0.0" } }, "sha512-En41P6cDHcHtQ0nvfsn9ayB+8ahQJqG1nzvPX8FVZjOriFK/RtZPQBtXMfZDq/AsVIk7JFZGFEtAVEmztNJVhQ=="],
|
||||
|
||||
"exact-mirror": ["exact-mirror@0.1.2", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-wFCPCDLmHbKGUb8TOi/IS7jLsgR8WVDGtDK3CzcB4Guf/weq7G+I+DkXiRSZfbemBFOxOINKpraM6ml78vo8Zw=="],
|
||||
@ -36,14 +42,36 @@
|
||||
|
||||
"file-type": ["file-type@21.0.0", "", { "dependencies": { "@tokenizer/inflate": "^0.2.7", "strtok3": "^10.2.2", "token-types": "^6.0.0", "uint8array-extras": "^1.4.0" } }, "sha512-ek5xNX2YBYlXhiUXui3D/BXa3LdqPmoLJ7rqEx2bKJ7EAUEfmXgW0Das7Dc6Nr9MvqaOnIqiPV0mZk/r/UpNAg=="],
|
||||
|
||||
"generate-function": ["generate-function@2.3.1", "", { "dependencies": { "is-property": "^1.0.2" } }, "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ=="],
|
||||
|
||||
"iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
|
||||
|
||||
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
|
||||
|
||||
"is-property": ["is-property@1.0.2", "", {}, "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g=="],
|
||||
|
||||
"long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
|
||||
|
||||
"lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="],
|
||||
|
||||
"lru.min": ["lru.min@1.1.2", "", {}, "sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"mysql2": ["mysql2@3.14.1", "", { "dependencies": { "aws-ssl-profiles": "^1.1.1", "denque": "^2.1.0", "generate-function": "^2.3.1", "iconv-lite": "^0.6.3", "long": "^5.2.1", "lru.min": "^1.0.0", "named-placeholders": "^1.1.3", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" } }, "sha512-7ytuPQJjQB8TNAYX/H2yhL+iQOnIBjAMam361R7UAL0lOVXWjtdrmoL9HYKqKoLp/8UUTRcvo1QPvK9KL7wA8w=="],
|
||||
|
||||
"named-placeholders": ["named-placeholders@1.1.3", "", { "dependencies": { "lru-cache": "^7.14.1" } }, "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w=="],
|
||||
|
||||
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
|
||||
|
||||
"peek-readable": ["peek-readable@7.0.0", "", {}, "sha512-nri2TO5JE3/mRryik9LlHFT53cgHfRK0Lt0BAZQXku/AW3E6XLt2GaY8siWi7dvW/m1z0ecn+J+bpDa9ZN3IsQ=="],
|
||||
|
||||
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
|
||||
|
||||
"seq-queue": ["seq-queue@0.0.5", "", {}, "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="],
|
||||
|
||||
"sqlstring": ["sqlstring@2.3.3", "", {}, "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="],
|
||||
|
||||
"strtok3": ["strtok3@10.2.2", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "peek-readable": "^7.0.0" } }, "sha512-Xt18+h4s7Z8xyZ0tmBoRmzxcop97R4BAh+dXouUDCYn+Em+1P3qpkUfI5ueWLT8ynC5hZ+q4iPEmGG1urvQGBg=="],
|
||||
|
||||
"token-types": ["token-types@6.0.0", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA=="],
|
||||
@ -53,5 +81,7 @@
|
||||
"uint8array-extras": ["uint8array-extras@1.4.0", "", {}, "sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ=="],
|
||||
|
||||
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||
|
||||
"bun-types/@types/node": ["@types/node@22.15.21", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ=="],
|
||||
}
|
||||
}
|
||||
|
@ -6,9 +6,11 @@
|
||||
"dev": "bun run --watch src/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"elysia": "latest"
|
||||
"elysia": "latest",
|
||||
"mysql2": "^3.14.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.15.29",
|
||||
"bun-types": "latest"
|
||||
},
|
||||
"module": "src/index.js"
|
||||
|
121
src/index.ts
121
src/index.ts
@ -1,4 +1,18 @@
|
||||
import { Elysia, t } from "elysia";
|
||||
import mysql from "mysql2/promise";
|
||||
|
||||
const pool = mysql.createPool({
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
});
|
||||
|
||||
type Member = {
|
||||
id: number;
|
||||
name: string;
|
||||
phone: string;
|
||||
};
|
||||
|
||||
// dummy data
|
||||
const data = {
|
||||
@ -7,81 +21,118 @@ const data = {
|
||||
|
||||
const app = new Elysia().get("/", () => "Hello Elysia").listen(3000);
|
||||
|
||||
app.group("/api", (app) => {
|
||||
return app
|
||||
app.group("/api", (api) => {
|
||||
return api
|
||||
.post(
|
||||
"/create",
|
||||
({ body: { food } }) => {
|
||||
data.foods.push(food);
|
||||
async ({ body }) => {
|
||||
const { name, phone } = body;
|
||||
if (!name || !phone) {
|
||||
return {
|
||||
status: "error",
|
||||
message: "Name and phone are required.",
|
||||
};
|
||||
}
|
||||
|
||||
const id = data.foods.length - 1;
|
||||
const [res] = await pool.execute(
|
||||
"INSERT INTO `member` (name, phone) VALUES (?, ?)",
|
||||
[name, phone]
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: `${food} is added to the list.`,
|
||||
message: `${name} is added to the list.`,
|
||||
data: {
|
||||
id,
|
||||
food: data.foods[id],
|
||||
},
|
||||
name,
|
||||
phone,
|
||||
} as Omit<Member, "id">,
|
||||
};
|
||||
},
|
||||
{
|
||||
body: t.Object({
|
||||
food: t.String(),
|
||||
name: t.String(),
|
||||
phone: t.String(),
|
||||
}),
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
.get("/read", () => ({
|
||||
status: "success",
|
||||
message: "Reading foods.",
|
||||
data: data.foods,
|
||||
}))
|
||||
.get("/read", async () => {
|
||||
const [rows] = await pool.query<any[]>("SELECT * FROM `member`");
|
||||
|
||||
if (rows.length === 0) {
|
||||
return {
|
||||
status: "error",
|
||||
message: "No members found.",
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: "Members collected.",
|
||||
data: rows as Member[],
|
||||
};
|
||||
})
|
||||
|
||||
.put(
|
||||
"/update",
|
||||
({ body: { food, id } }) => {
|
||||
if (data.foods[id] === undefined) {
|
||||
async ({ body }) => {
|
||||
const { id, name, phone } = body;
|
||||
|
||||
const [res] = await pool.execute<mysql.ResultSetHeader>(
|
||||
"UPDATE `member` SET name = ?, phone = ? WHERE id = ?",
|
||||
[name, phone, id]
|
||||
);
|
||||
|
||||
if (res.affectedRows === 0) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `${id} does not exist.`,
|
||||
message: `Member with ID ${id} not found.`,
|
||||
};
|
||||
}
|
||||
data.foods[id] = food;
|
||||
|
||||
const [rows] = await pool.query<any[]>(
|
||||
"SELECT * FROM `member` WHERE id = ?",
|
||||
[id]
|
||||
);
|
||||
return {
|
||||
status: "success",
|
||||
message: `${food} is updated.`,
|
||||
data: {
|
||||
food: data.foods[id],
|
||||
},
|
||||
message: `Member with ID ${id} is updated.`,
|
||||
data: rows[0],
|
||||
};
|
||||
},
|
||||
{
|
||||
body: t.Object({
|
||||
id: t.Number(),
|
||||
food: t.String(),
|
||||
name: t.String(),
|
||||
phone: t.String(),
|
||||
}),
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
.delete(
|
||||
"/delete",
|
||||
({ body: { id } }) => {
|
||||
const deleted = data.foods.splice(id, 1);
|
||||
|
||||
async ({ body: { id } }) => {
|
||||
const [rows] = await pool.query<any[]>(
|
||||
"SELECT * FROM `member` WHERE id = ?",
|
||||
[id]
|
||||
);
|
||||
if (rows.length === 0) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Member with ID ${id} not found.`,
|
||||
};
|
||||
}
|
||||
await pool.execute("DELETE FROM `member` WHERE id = ?", [id]);
|
||||
return {
|
||||
status: "success",
|
||||
message: `${deleted[0]} is deleted.`,
|
||||
data: {
|
||||
food: deleted[0],
|
||||
},
|
||||
message: `Member with ID ${id} is deleted.`,
|
||||
data: rows[0],
|
||||
};
|
||||
},
|
||||
{ body: t.Object({ id: t.Number() }) },
|
||||
{ body: t.Object({ id: t.Number() }) }
|
||||
);
|
||||
});
|
||||
|
||||
console.log(
|
||||
`🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`,
|
||||
`🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user