deploy-bbc 1.2.4 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -4
- package/dist/index.js +122 -67
- package/dist/templates/base/.env.example +1 -1
- package/dist/templates/base/package.json +2 -1
- package/dist/templates/base/src/config/index.ts +1 -1
- package/dist/templates/base/src/controllers/user/create-user.controller.ts +84 -0
- package/dist/templates/base/src/controllers/user/delete-user.controller.ts +60 -0
- package/dist/templates/base/src/controllers/user/get-user.controller.ts +74 -0
- package/dist/templates/base/src/controllers/user/get-users.controller.ts +41 -0
- package/dist/templates/base/src/controllers/user/update-user.controller.ts +111 -0
- package/dist/templates/base/src/models/user.model.ts +83 -0
- package/dist/templates/base/src/routes/index.ts +5 -0
- package/dist/templates/base/src/routes/user.route.ts +17 -0
- package/dist/templates/base/src/types/common/api-response.types.ts +30 -0
- package/dist/templates/base/src/types/index.ts +5 -2
- package/dist/templates/base/src/types/models/user.types.ts +26 -0
- package/dist/templates/base-bun-native/.env.example +1 -1
- package/dist/templates/base-bun-native/package.json +2 -1
- package/dist/templates/base-bun-native/src/config/index.ts +1 -1
- package/dist/templates/base-bun-native/src/controllers/user/create-user.controller.ts +76 -0
- package/dist/templates/base-bun-native/src/controllers/user/delete-user.controller.ts +53 -0
- package/dist/templates/base-bun-native/src/controllers/user/get-user.controller.ts +67 -0
- package/dist/templates/base-bun-native/src/controllers/user/get-users.controller.ts +40 -0
- package/dist/templates/base-bun-native/src/controllers/user/update-user.controller.ts +101 -0
- package/dist/templates/base-bun-native/src/index.ts +3 -3
- package/dist/templates/base-bun-native/src/models/user.model.ts +83 -0
- package/dist/templates/base-bun-native/src/routes/index.ts +10 -6
- package/dist/templates/base-bun-native/src/routes/user.route.ts +50 -0
- package/dist/templates/base-bun-native/src/types/common/api-response.types.ts +30 -0
- package/dist/templates/base-bun-native/src/types/index.ts +5 -2
- package/dist/templates/base-bun-native/src/types/models/user.types.ts +26 -0
- package/dist/templates/base-express/.env.example +1 -1
- package/dist/templates/base-express/package.json +2 -1
- package/dist/templates/base-express/src/config/index.ts +1 -1
- package/dist/templates/base-express/src/controllers/user/create-user.controller.ts +75 -0
- package/dist/templates/base-express/src/controllers/user/delete-user.controller.ts +56 -0
- package/dist/templates/base-express/src/controllers/user/get-user.controller.ts +70 -0
- package/dist/templates/base-express/src/controllers/user/get-users.controller.ts +41 -0
- package/dist/templates/base-express/src/controllers/user/update-user.controller.ts +102 -0
- package/dist/templates/base-express/src/models/user.model.ts +83 -0
- package/dist/templates/base-express/src/routes/index.ts +5 -0
- package/dist/templates/base-express/src/routes/user.route.ts +17 -0
- package/dist/templates/base-express/src/types/common/api-response.types.ts +30 -0
- package/dist/templates/base-express/src/types/index.ts +5 -2
- package/dist/templates/base-express/src/types/models/user.types.ts +26 -0
- package/dist/templates/extras/database/mongodb/src/db/index.ts +70 -0
- package/dist/templates/extras/database/mongodb/src/db/models/user.model.ts +87 -0
- package/dist/templates/extras/database/mysql/src/db/index.ts +106 -0
- package/dist/templates/extras/database/postgres/src/db/index.ts +96 -0
- package/dist/templates/extras/database/redis/src/db/redis.ts +215 -0
- package/dist/templates/extras/database/sqlite/src/db/index.ts +185 -0
- package/dist/templates/templates/base/.dockerignore +45 -0
- package/dist/templates/templates/base/src/models/user.model.ts +1 -1
- package/dist/templates/templates/base-bun-native/.dockerignore +45 -0
- package/dist/templates/templates/base-bun-native/src/models/user.model.ts +1 -1
- package/dist/templates/templates/base-express/.dockerignore +45 -0
- package/dist/templates/templates/base-express/src/models/user.model.ts +1 -1
- package/dist/templates/templates/extras/database/mongodb/src/db/index.ts +70 -0
- package/dist/templates/templates/extras/database/mongodb/src/db/models/user.model.ts +87 -0
- package/dist/templates/templates/extras/database/mysql/src/db/index.ts +106 -0
- package/dist/templates/templates/extras/database/postgres/src/db/index.ts +96 -0
- package/dist/templates/templates/extras/database/redis/src/db/redis.ts +215 -0
- package/dist/templates/templates/extras/database/sqlite/src/db/index.ts +185 -0
- package/package.json +1 -1
- package/dist/templates/extras/database/mysql/drizzle.config.ts +0 -0
- package/dist/templates/templates/extras/database/mysql/drizzle.config.ts +0 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { Request, Response } from "express";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { user_model } from "../../models/user.model.js";
|
|
4
|
+
import type { ApiResponse, ApiError } from "../../types/common/api-response.types.js";
|
|
5
|
+
import type { UserResponse } from "../../types/models/user.types.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Validation schemas
|
|
9
|
+
*/
|
|
10
|
+
const user_id_schema = z.string().uuid("Invalid user ID format");
|
|
11
|
+
const update_user_schema = z.object({
|
|
12
|
+
email: z.string().email("Invalid email address").optional(),
|
|
13
|
+
name: z.string().min(2, "Name must be at least 2 characters").max(100, "Name must not exceed 100 characters").optional(),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Helper to format user response
|
|
18
|
+
*/
|
|
19
|
+
function format_user_response(user: any): UserResponse {
|
|
20
|
+
return {
|
|
21
|
+
id: user.id,
|
|
22
|
+
email: user.email,
|
|
23
|
+
name: user.name,
|
|
24
|
+
createdAt: user.createdAt.toISOString(),
|
|
25
|
+
updatedAt: user.updatedAt.toISOString(),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Update user by ID
|
|
31
|
+
* PATCH /users/:id
|
|
32
|
+
*/
|
|
33
|
+
export async function update_user(req: Request, res: Response) {
|
|
34
|
+
try {
|
|
35
|
+
const { id } = req.params;
|
|
36
|
+
|
|
37
|
+
// Validate ID format
|
|
38
|
+
const id_validation = user_id_schema.safeParse(id);
|
|
39
|
+
if (!id_validation.success) {
|
|
40
|
+
const errorResponse: ApiError = {
|
|
41
|
+
success: false,
|
|
42
|
+
error: "Invalid user ID",
|
|
43
|
+
details: id_validation.error.errors.map((err) => ({
|
|
44
|
+
field: err.path.join("."),
|
|
45
|
+
message: err.message,
|
|
46
|
+
})),
|
|
47
|
+
};
|
|
48
|
+
return res.status(400).json(errorResponse);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Validate request body
|
|
52
|
+
const body_validation = update_user_schema.safeParse(req.body);
|
|
53
|
+
if (!body_validation.success) {
|
|
54
|
+
const errorResponse: ApiError = {
|
|
55
|
+
success: false,
|
|
56
|
+
error: "Validation failed",
|
|
57
|
+
details: body_validation.error.errors.map((err) => ({
|
|
58
|
+
field: err.path.join("."),
|
|
59
|
+
message: err.message,
|
|
60
|
+
})),
|
|
61
|
+
};
|
|
62
|
+
return res.status(400).json(errorResponse);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Check if email is being updated and if it already exists
|
|
66
|
+
if (body_validation.data.email) {
|
|
67
|
+
const existing_user = await user_model.find_by_email(body_validation.data.email);
|
|
68
|
+
if (existing_user && existing_user.id !== id) {
|
|
69
|
+
const errorResponse: ApiError = {
|
|
70
|
+
success: false,
|
|
71
|
+
error: "User with this email already exists",
|
|
72
|
+
};
|
|
73
|
+
return res.status(409).json(errorResponse);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Update user
|
|
78
|
+
const user = await user_model.update(id, body_validation.data);
|
|
79
|
+
|
|
80
|
+
if (!user) {
|
|
81
|
+
const errorResponse: ApiError = {
|
|
82
|
+
success: false,
|
|
83
|
+
error: "User not found",
|
|
84
|
+
};
|
|
85
|
+
return res.status(404).json(errorResponse);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const response: ApiResponse<UserResponse> = {
|
|
89
|
+
success: true,
|
|
90
|
+
data: format_user_response(user),
|
|
91
|
+
message: "User updated successfully",
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
res.json(response);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
const errorResponse: ApiError = {
|
|
97
|
+
success: false,
|
|
98
|
+
error: "Failed to update user",
|
|
99
|
+
};
|
|
100
|
+
res.status(500).json(errorResponse);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { User, CreateUserInput, UpdateUserInput } from "../types/models/user.types.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* User model
|
|
5
|
+
*
|
|
6
|
+
* This is a simple in-memory implementation.
|
|
7
|
+
* Replace with your actual database implementation in production.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// In-memory storage (for demonstration)
|
|
11
|
+
const users: User[] = [];
|
|
12
|
+
|
|
13
|
+
export const user_model = {
|
|
14
|
+
/**
|
|
15
|
+
* Find all users
|
|
16
|
+
*/
|
|
17
|
+
find_all: async (): Promise<User[]> => {
|
|
18
|
+
return users;
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Find user by ID
|
|
23
|
+
*/
|
|
24
|
+
find_by_id: async (id: string): Promise<User | undefined> => {
|
|
25
|
+
return users.find((user) => user.id === id);
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Find user by email
|
|
30
|
+
*/
|
|
31
|
+
find_by_email: async (email: string): Promise<User | undefined> => {
|
|
32
|
+
return users.find((user) => user.email === email);
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Create a new user
|
|
37
|
+
*/
|
|
38
|
+
create: async (input: CreateUserInput): Promise<User> => {
|
|
39
|
+
const user: User = {
|
|
40
|
+
id: crypto.randomUUID(),
|
|
41
|
+
email: input.email,
|
|
42
|
+
name: input.name,
|
|
43
|
+
createdAt: new Date(),
|
|
44
|
+
updatedAt: new Date(),
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
users.push(user);
|
|
48
|
+
return user;
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Update user by ID
|
|
53
|
+
*/
|
|
54
|
+
update: async (id: string, input: UpdateUserInput): Promise<User | undefined> => {
|
|
55
|
+
const index = users.findIndex((user) => user.id === id);
|
|
56
|
+
|
|
57
|
+
if (index === -1) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
users[index] = {
|
|
62
|
+
...users[index],
|
|
63
|
+
...input,
|
|
64
|
+
updatedAt: new Date(),
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
return users[index];
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Delete user by ID
|
|
72
|
+
*/
|
|
73
|
+
delete: async (id: string): Promise<boolean> => {
|
|
74
|
+
const index = users.findIndex((user) => user.id === id);
|
|
75
|
+
|
|
76
|
+
if (index === -1) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
users.splice(index, 1);
|
|
81
|
+
return true;
|
|
82
|
+
},
|
|
83
|
+
};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import express from "express";
|
|
2
|
+
import user_route from "./user.route.js";
|
|
2
3
|
|
|
3
4
|
const router = express.Router();
|
|
4
5
|
|
|
6
|
+
// Root route
|
|
5
7
|
router.get("/", (req, res) => {
|
|
6
8
|
res.json({
|
|
7
9
|
message: "Welcome to your Bun backend!",
|
|
@@ -9,4 +11,7 @@ router.get("/", (req, res) => {
|
|
|
9
11
|
});
|
|
10
12
|
});
|
|
11
13
|
|
|
14
|
+
// User routes
|
|
15
|
+
router.use("/users", user_route);
|
|
16
|
+
|
|
12
17
|
export default router;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import { get_users } from "../controllers/user/get-users.controller.js";
|
|
3
|
+
import { get_user } from "../controllers/user/get-user.controller.js";
|
|
4
|
+
import { create_user } from "../controllers/user/create-user.controller.js";
|
|
5
|
+
import { update_user } from "../controllers/user/update-user.controller.js";
|
|
6
|
+
import { delete_user } from "../controllers/user/delete-user.controller.js";
|
|
7
|
+
|
|
8
|
+
const user_route = express.Router();
|
|
9
|
+
|
|
10
|
+
// User CRUD routes
|
|
11
|
+
user_route.get("/", get_users);
|
|
12
|
+
user_route.get("/:id", get_user);
|
|
13
|
+
user_route.post("/", create_user);
|
|
14
|
+
user_route.patch("/:id", update_user);
|
|
15
|
+
user_route.delete("/:id", delete_user);
|
|
16
|
+
|
|
17
|
+
export default user_route;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common API response types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface ApiResponse<T = unknown> {
|
|
6
|
+
success: boolean;
|
|
7
|
+
data?: T;
|
|
8
|
+
error?: string;
|
|
9
|
+
message?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface PaginatedResponse<T> extends ApiResponse<T[]> {
|
|
13
|
+
pagination: {
|
|
14
|
+
page: number;
|
|
15
|
+
limit: number;
|
|
16
|
+
total: number;
|
|
17
|
+
totalPages: number;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ValidationError {
|
|
22
|
+
field: string;
|
|
23
|
+
message: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface ApiError {
|
|
27
|
+
success: false;
|
|
28
|
+
error: string;
|
|
29
|
+
details?: ValidationError[];
|
|
30
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User model types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface User {
|
|
6
|
+
id: string;
|
|
7
|
+
email: string;
|
|
8
|
+
name: string;
|
|
9
|
+
createdAt: Date;
|
|
10
|
+
updatedAt: Date;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface CreateUserInput {
|
|
14
|
+
email: string;
|
|
15
|
+
name: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface UpdateUserInput {
|
|
19
|
+
email?: string;
|
|
20
|
+
name?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type UserResponse = Omit<User, "createdAt" | "updatedAt"> & {
|
|
24
|
+
createdAt: string;
|
|
25
|
+
updatedAt: string;
|
|
26
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import mongoose from "mongoose";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MongoDB database connection using Mongoose
|
|
5
|
+
* Docs: https://mongoosejs.com/docs/connections.html
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const MONGODB_URI = process.env.MONGODB_URI;
|
|
9
|
+
|
|
10
|
+
if (!MONGODB_URI) {
|
|
11
|
+
throw new Error("MONGODB_URI environment variable is required");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Connect to MongoDB
|
|
16
|
+
*/
|
|
17
|
+
export async function connect_mongodb(): Promise<void> {
|
|
18
|
+
try {
|
|
19
|
+
await mongoose.connect(MONGODB_URI, {
|
|
20
|
+
maxPoolSize: 10, // Maximum number of connections in the pool
|
|
21
|
+
minPoolSize: 2, // Minimum number of connections
|
|
22
|
+
serverSelectionTimeoutMS: 5000, // Timeout for initial connection
|
|
23
|
+
socketTimeoutMS: 45000, // Socket timeout
|
|
24
|
+
});
|
|
25
|
+
console.log("✅ MongoDB connected successfully");
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error("❌ MongoDB connection failed:", error);
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Disconnect from MongoDB
|
|
34
|
+
* Call this when shutting down the application
|
|
35
|
+
*/
|
|
36
|
+
export async function disconnect_mongodb(): Promise<void> {
|
|
37
|
+
await mongoose.disconnect();
|
|
38
|
+
console.log("MongoDB connection closed");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Test database connection
|
|
43
|
+
*/
|
|
44
|
+
export async function test_connection(): Promise<boolean> {
|
|
45
|
+
try {
|
|
46
|
+
if (mongoose.connection.readyState !== 1) {
|
|
47
|
+
await connect_mongodb();
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error("❌ MongoDB connection test failed:", error);
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Connection event listeners
|
|
57
|
+
mongoose.connection.on("connected", () => {
|
|
58
|
+
console.log("Mongoose connected to MongoDB");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
mongoose.connection.on("error", (err) => {
|
|
62
|
+
console.error("Mongoose connection error:", err);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
mongoose.connection.on("disconnected", () => {
|
|
66
|
+
console.log("Mongoose disconnected from MongoDB");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Export mongoose instance for model creation
|
|
70
|
+
export { mongoose };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Schema, model, Document } from "mongoose";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* User interface for TypeScript
|
|
5
|
+
*/
|
|
6
|
+
export type User = {
|
|
7
|
+
email: string;
|
|
8
|
+
name: string;
|
|
9
|
+
createdAt?: Date;
|
|
10
|
+
updatedAt?: Date;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* User document interface (Mongoose Document + User)
|
|
15
|
+
*/
|
|
16
|
+
export type UserDocument = Document & User;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* User schema definition
|
|
20
|
+
*/
|
|
21
|
+
const user_schema = new Schema<UserDocument>(
|
|
22
|
+
{
|
|
23
|
+
email: {
|
|
24
|
+
type: String,
|
|
25
|
+
required: [true, "Email is required"],
|
|
26
|
+
unique: true,
|
|
27
|
+
lowercase: true,
|
|
28
|
+
trim: true,
|
|
29
|
+
match: [/^\S+@\S+\.\S+$/, "Please provide a valid email"],
|
|
30
|
+
},
|
|
31
|
+
name: {
|
|
32
|
+
type: String,
|
|
33
|
+
required: [true, "Name is required"],
|
|
34
|
+
trim: true,
|
|
35
|
+
minlength: [2, "Name must be at least 2 characters"],
|
|
36
|
+
maxlength: [100, "Name cannot exceed 100 characters"],
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
timestamps: true, // Automatically add createdAt and updatedAt
|
|
41
|
+
versionKey: false, // Disable __v field
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Indexes for better query performance
|
|
47
|
+
*/
|
|
48
|
+
user_schema.index({ email: 1 });
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* User model
|
|
52
|
+
*/
|
|
53
|
+
export const user_model = model<UserDocument>("User", user_schema);
|
|
54
|
+
|
|
55
|
+
// Example usage functions
|
|
56
|
+
/*
|
|
57
|
+
// Create a new user
|
|
58
|
+
export async function create_user(email: string, name: string) {
|
|
59
|
+
const user = new user_model({ email, name });
|
|
60
|
+
return await user.save();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Find all users
|
|
64
|
+
export async function find_all_users() {
|
|
65
|
+
return await user_model.find();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Find user by ID
|
|
69
|
+
export async function find_user_by_id(id: string) {
|
|
70
|
+
return await user_model.findById(id);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Find user by email
|
|
74
|
+
export async function find_user_by_email(email: string) {
|
|
75
|
+
return await user_model.findOne({ email });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Update user
|
|
79
|
+
export async function update_user(id: string, data: Partial<User>) {
|
|
80
|
+
return await user_model.findByIdAndUpdate(id, data, { new: true });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Delete user
|
|
84
|
+
export async function delete_user(id: string) {
|
|
85
|
+
return await user_model.findByIdAndDelete(id);
|
|
86
|
+
}
|
|
87
|
+
*/
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import mysql from "mysql2/promise";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MySQL database connection using mysql2 (optimized for Bun)
|
|
5
|
+
* Docs: https://github.com/sidorares/node-mysql2
|
|
6
|
+
* Note: mysql2 works natively with Bun and provides excellent performance
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const DATABASE_URL = process.env.DATABASE_URL;
|
|
10
|
+
|
|
11
|
+
if (!DATABASE_URL) {
|
|
12
|
+
throw new Error("DATABASE_URL environment variable is required");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Create MySQL connection pool
|
|
17
|
+
* Supports automatic reconnection and connection reuse
|
|
18
|
+
*/
|
|
19
|
+
export const pool = mysql.createPool({
|
|
20
|
+
uri: DATABASE_URL,
|
|
21
|
+
waitForConnections: true,
|
|
22
|
+
connectionLimit: 10, // Maximum number of connections
|
|
23
|
+
queueLimit: 0, // Unlimited queueing
|
|
24
|
+
enableKeepAlive: true,
|
|
25
|
+
keepAliveInitialDelay: 0,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Get a connection from the pool for executing queries
|
|
30
|
+
* Use this for single queries or simple operations
|
|
31
|
+
*/
|
|
32
|
+
export async function query(sql: string, params?: any[]) {
|
|
33
|
+
const [rows] = await pool.execute(sql, params);
|
|
34
|
+
return rows;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Test database connection
|
|
39
|
+
*/
|
|
40
|
+
export async function test_connection(): Promise<boolean> {
|
|
41
|
+
try {
|
|
42
|
+
await pool.query("SELECT 1");
|
|
43
|
+
console.log("✅ MySQL connected successfully");
|
|
44
|
+
return true;
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error("❌ MySQL connection failed:", error);
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Close database connection pool
|
|
53
|
+
* Call this when shutting down the application
|
|
54
|
+
*/
|
|
55
|
+
export async function close_connection(): Promise<void> {
|
|
56
|
+
await pool.end();
|
|
57
|
+
console.log("MySQL connection pool closed");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Example queries - uncomment and modify as needed
|
|
61
|
+
/*
|
|
62
|
+
// Create users table
|
|
63
|
+
export async function create_users_table() {
|
|
64
|
+
await query(`
|
|
65
|
+
CREATE TABLE IF NOT EXISTS users (
|
|
66
|
+
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
67
|
+
email VARCHAR(255) UNIQUE NOT NULL,
|
|
68
|
+
name VARCHAR(255) NOT NULL,
|
|
69
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
70
|
+
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
71
|
+
)
|
|
72
|
+
`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Get all users
|
|
76
|
+
export async function get_all_users() {
|
|
77
|
+
return await query("SELECT * FROM users");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Get user by ID
|
|
81
|
+
export async function get_user_by_id(id: number) {
|
|
82
|
+
return await query("SELECT * FROM users WHERE id = ?", [id]);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Create user
|
|
86
|
+
export async function create_user(email: string, name: string) {
|
|
87
|
+
const result = await query(
|
|
88
|
+
"INSERT INTO users (email, name) VALUES (?, ?)",
|
|
89
|
+
[email, name]
|
|
90
|
+
);
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Update user
|
|
95
|
+
export async function update_user(id: number, email: string, name: string) {
|
|
96
|
+
return await query(
|
|
97
|
+
"UPDATE users SET email = ?, name = ? WHERE id = ?",
|
|
98
|
+
[email, name, id]
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Delete user
|
|
103
|
+
export async function delete_user(id: number) {
|
|
104
|
+
return await query("DELETE FROM users WHERE id = ?", [id]);
|
|
105
|
+
}
|
|
106
|
+
*/
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import postgres from "postgres";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* PostgreSQL database connection using the native postgres driver
|
|
5
|
+
* Docs: https://github.com/porsager/postgres
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const DATABASE_URL = process.env.DATABASE_URL;
|
|
9
|
+
|
|
10
|
+
if (!DATABASE_URL) {
|
|
11
|
+
throw new Error("DATABASE_URL environment variable is required");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Create PostgreSQL connection instance
|
|
16
|
+
* Supports connection pooling and automatic reconnection
|
|
17
|
+
*/
|
|
18
|
+
export const sql = postgres(DATABASE_URL, {
|
|
19
|
+
max: 10, // Maximum number of connections in the pool
|
|
20
|
+
idle_timeout: 20, // Idle connection timeout in seconds
|
|
21
|
+
connect_timeout: 10, // Connection timeout in seconds
|
|
22
|
+
onnotice: () => {}, // Suppress notices
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Test database connection
|
|
27
|
+
*/
|
|
28
|
+
export async function test_connection(): Promise<boolean> {
|
|
29
|
+
try {
|
|
30
|
+
await sql`SELECT 1`;
|
|
31
|
+
console.log("✅ PostgreSQL connected successfully");
|
|
32
|
+
return true;
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error("❌ PostgreSQL connection failed:", error);
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Close database connection
|
|
41
|
+
* Call this when shutting down the application
|
|
42
|
+
*/
|
|
43
|
+
export async function close_connection(): Promise<void> {
|
|
44
|
+
await sql.end({ timeout: 5 });
|
|
45
|
+
console.log("PostgreSQL connection closed");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Example queries - uncomment and modify as needed
|
|
49
|
+
/*
|
|
50
|
+
// Create users table
|
|
51
|
+
export async function create_users_table() {
|
|
52
|
+
await sql`
|
|
53
|
+
CREATE TABLE IF NOT EXISTS users (
|
|
54
|
+
id SERIAL PRIMARY KEY,
|
|
55
|
+
email VARCHAR(255) UNIQUE NOT NULL,
|
|
56
|
+
name VARCHAR(255) NOT NULL,
|
|
57
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
58
|
+
updated_at TIMESTAMP DEFAULT NOW()
|
|
59
|
+
)
|
|
60
|
+
`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Get all users
|
|
64
|
+
export async function get_all_users() {
|
|
65
|
+
return await sql`SELECT * FROM users`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Get user by ID
|
|
69
|
+
export async function get_user_by_id(id: number) {
|
|
70
|
+
return await sql`SELECT * FROM users WHERE id = ${id}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Create user
|
|
74
|
+
export async function create_user(email: string, name: string) {
|
|
75
|
+
return await sql`
|
|
76
|
+
INSERT INTO users (email, name)
|
|
77
|
+
VALUES (${email}, ${name})
|
|
78
|
+
RETURNING *
|
|
79
|
+
`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Update user
|
|
83
|
+
export async function update_user(id: number, email: string, name: string) {
|
|
84
|
+
return await sql`
|
|
85
|
+
UPDATE users
|
|
86
|
+
SET email = ${email}, name = ${name}, updated_at = NOW()
|
|
87
|
+
WHERE id = ${id}
|
|
88
|
+
RETURNING *
|
|
89
|
+
`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Delete user
|
|
93
|
+
export async function delete_user(id: number) {
|
|
94
|
+
return await sql`DELETE FROM users WHERE id = ${id}`;
|
|
95
|
+
}
|
|
96
|
+
*/
|