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,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
|
+
*/
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { createClient } from "redis";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Redis client setup
|
|
5
|
+
* Docs: https://github.com/redis/node-redis
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const REDIS_URL = process.env.REDIS_URL || "redis://localhost:6379";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Create Redis client instance
|
|
12
|
+
*/
|
|
13
|
+
export const redis_client = createClient({
|
|
14
|
+
url: REDIS_URL,
|
|
15
|
+
socket: {
|
|
16
|
+
reconnectStrategy: (retries) => {
|
|
17
|
+
if (retries > 10) {
|
|
18
|
+
console.error("❌ Redis connection failed after 10 retries");
|
|
19
|
+
return new Error("Redis connection failed");
|
|
20
|
+
}
|
|
21
|
+
// Exponential backoff: 50ms, 100ms, 200ms, etc.
|
|
22
|
+
return Math.min(retries * 50, 3000);
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Connect to Redis
|
|
29
|
+
*/
|
|
30
|
+
export async function connect_redis(): Promise<void> {
|
|
31
|
+
try {
|
|
32
|
+
await redis_client.connect();
|
|
33
|
+
console.log("✅ Redis connected successfully");
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error("❌ Redis connection failed:", error);
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Disconnect from Redis
|
|
42
|
+
* Call this when shutting down the application
|
|
43
|
+
*/
|
|
44
|
+
export async function disconnect_redis(): Promise<void> {
|
|
45
|
+
await redis_client.quit();
|
|
46
|
+
console.log("Redis connection closed");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Test Redis connection
|
|
51
|
+
*/
|
|
52
|
+
export async function test_connection(): Promise<boolean> {
|
|
53
|
+
try {
|
|
54
|
+
await redis_client.ping();
|
|
55
|
+
console.log("✅ Redis ping successful");
|
|
56
|
+
return true;
|
|
57
|
+
} catch (error) {
|
|
58
|
+
console.error("❌ Redis ping failed:", error);
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Event listeners
|
|
64
|
+
redis_client.on("error", (err) => {
|
|
65
|
+
console.error("Redis Client Error:", err);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
redis_client.on("connect", () => {
|
|
69
|
+
console.log("Redis client connected");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
redis_client.on("ready", () => {
|
|
73
|
+
console.log("Redis client ready");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
redis_client.on("reconnecting", () => {
|
|
77
|
+
console.log("Redis client reconnecting...");
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Helper functions for common operations
|
|
81
|
+
export const redis = {
|
|
82
|
+
/**
|
|
83
|
+
* Set a key-value pair
|
|
84
|
+
*/
|
|
85
|
+
set: async (key: string, value: string, expireSeconds?: number) => {
|
|
86
|
+
if (expireSeconds) {
|
|
87
|
+
return await redis_client.setEx(key, expireSeconds, value);
|
|
88
|
+
}
|
|
89
|
+
return await redis_client.set(key, value);
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get value by key
|
|
94
|
+
*/
|
|
95
|
+
get: async (key: string) => {
|
|
96
|
+
return await redis_client.get(key);
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Delete a key
|
|
101
|
+
*/
|
|
102
|
+
del: async (key: string) => {
|
|
103
|
+
return await redis_client.del(key);
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Check if key exists
|
|
108
|
+
*/
|
|
109
|
+
exists: async (key: string) => {
|
|
110
|
+
return await redis_client.exists(key);
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Set expiration on a key
|
|
115
|
+
*/
|
|
116
|
+
expire: async (key: string, seconds: number) => {
|
|
117
|
+
return await redis_client.expire(key, seconds);
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Get all keys matching pattern
|
|
122
|
+
*/
|
|
123
|
+
keys: async (pattern: string) => {
|
|
124
|
+
return await redis_client.keys(pattern);
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Increment a value
|
|
129
|
+
*/
|
|
130
|
+
incr: async (key: string) => {
|
|
131
|
+
return await redis_client.incr(key);
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Decrement a value
|
|
136
|
+
*/
|
|
137
|
+
decr: async (key: string) => {
|
|
138
|
+
return await redis_client.decr(key);
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Hash operations
|
|
143
|
+
*/
|
|
144
|
+
hash: {
|
|
145
|
+
set: async (key: string, field: string, value: string) => {
|
|
146
|
+
return await redis_client.hSet(key, field, value);
|
|
147
|
+
},
|
|
148
|
+
get: async (key: string, field: string) => {
|
|
149
|
+
return await redis_client.hGet(key, field);
|
|
150
|
+
},
|
|
151
|
+
getAll: async (key: string) => {
|
|
152
|
+
return await redis_client.hGetAll(key);
|
|
153
|
+
},
|
|
154
|
+
del: async (key: string, field: string) => {
|
|
155
|
+
return await redis_client.hDel(key, field);
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* List operations
|
|
161
|
+
*/
|
|
162
|
+
list: {
|
|
163
|
+
push: async (key: string, ...values: string[]) => {
|
|
164
|
+
return await redis_client.lPush(key, values);
|
|
165
|
+
},
|
|
166
|
+
pop: async (key: string) => {
|
|
167
|
+
return await redis_client.lPop(key);
|
|
168
|
+
},
|
|
169
|
+
range: async (key: string, start: number, stop: number) => {
|
|
170
|
+
return await redis_client.lRange(key, start, stop);
|
|
171
|
+
},
|
|
172
|
+
length: async (key: string) => {
|
|
173
|
+
return await redis_client.lLen(key);
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Set operations
|
|
179
|
+
*/
|
|
180
|
+
set_ops: {
|
|
181
|
+
add: async (key: string, ...members: string[]) => {
|
|
182
|
+
return await redis_client.sAdd(key, members);
|
|
183
|
+
},
|
|
184
|
+
members: async (key: string) => {
|
|
185
|
+
return await redis_client.sMembers(key);
|
|
186
|
+
},
|
|
187
|
+
isMember: async (key: string, member: string) => {
|
|
188
|
+
return await redis_client.sIsMember(key, member);
|
|
189
|
+
},
|
|
190
|
+
remove: async (key: string, ...members: string[]) => {
|
|
191
|
+
return await redis_client.sRem(key, members);
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
// Example usage:
|
|
197
|
+
/*
|
|
198
|
+
// Simple key-value
|
|
199
|
+
await redis.set("user:1:name", "John Doe");
|
|
200
|
+
await redis.set("session:abc123", "user_data", 3600); // Expires in 1 hour
|
|
201
|
+
const name = await redis.get("user:1:name");
|
|
202
|
+
|
|
203
|
+
// Hash (for objects)
|
|
204
|
+
await redis.hash.set("user:1", "email", "john@example.com");
|
|
205
|
+
await redis.hash.set("user:1", "age", "30");
|
|
206
|
+
const userData = await redis.hash.getAll("user:1");
|
|
207
|
+
|
|
208
|
+
// Lists (queues)
|
|
209
|
+
await redis.list.push("tasks", "task1", "task2");
|
|
210
|
+
const task = await redis.list.pop("tasks");
|
|
211
|
+
|
|
212
|
+
// Sets (unique values)
|
|
213
|
+
await redis.set_ops.add("online_users", "user1", "user2");
|
|
214
|
+
const isOnline = await redis.set_ops.isMember("online_users", "user1");
|
|
215
|
+
*/
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { Database } from "bun:sqlite";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SQLite database connection using Bun's built-in sqlite module
|
|
5
|
+
* Docs: https://bun.sh/docs/api/sqlite
|
|
6
|
+
*
|
|
7
|
+
* Benefits of bun:sqlite:
|
|
8
|
+
* - Zero dependencies (built into Bun)
|
|
9
|
+
* - Extremely fast (native implementation)
|
|
10
|
+
* - Type-safe prepared statements
|
|
11
|
+
* - Automatic statement caching
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const DATABASE_PATH = process.env.DATABASE_PATH || "./data/app.db";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create SQLite database instance
|
|
18
|
+
* Options:
|
|
19
|
+
* - create: true - creates the database file if it doesn't exist
|
|
20
|
+
* - readwrite: allows both reading and writing
|
|
21
|
+
* - strict: enables strict mode for better type safety
|
|
22
|
+
*/
|
|
23
|
+
export const db = new Database(DATABASE_PATH, {
|
|
24
|
+
create: true,
|
|
25
|
+
readwrite: true,
|
|
26
|
+
strict: true,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Enable Write-Ahead Logging (WAL) mode for better concurrency
|
|
30
|
+
db.run("PRAGMA journal_mode = WAL");
|
|
31
|
+
|
|
32
|
+
// Enable foreign key constraints
|
|
33
|
+
db.run("PRAGMA foreign_keys = ON");
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Test database connection
|
|
37
|
+
*/
|
|
38
|
+
export function test_connection(): boolean {
|
|
39
|
+
try {
|
|
40
|
+
const result = db.query("SELECT 1 as test").get() as { test: number };
|
|
41
|
+
console.log("✅ SQLite connected successfully");
|
|
42
|
+
return result.test === 1;
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error("❌ SQLite connection failed:", error);
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Close database connection
|
|
51
|
+
* Call this when shutting down the application
|
|
52
|
+
*/
|
|
53
|
+
export function close_connection(): void {
|
|
54
|
+
db.close();
|
|
55
|
+
console.log("SQLite connection closed");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Helper function to run migrations/DDL statements
|
|
60
|
+
*/
|
|
61
|
+
export function migrate(sql: string): void {
|
|
62
|
+
db.run(sql);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Example usage - uncomment and modify as needed
|
|
66
|
+
/*
|
|
67
|
+
// Create users table
|
|
68
|
+
export function create_users_table() {
|
|
69
|
+
db.run(`
|
|
70
|
+
CREATE TABLE IF NOT EXISTS users (
|
|
71
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
72
|
+
email TEXT UNIQUE NOT NULL,
|
|
73
|
+
name TEXT NOT NULL,
|
|
74
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
75
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
76
|
+
)
|
|
77
|
+
`);
|
|
78
|
+
|
|
79
|
+
// Create index on email
|
|
80
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_users_email ON users(email)`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Get all users
|
|
84
|
+
export function get_all_users() {
|
|
85
|
+
return db.query("SELECT * FROM users").all();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Get user by ID
|
|
89
|
+
export function get_user_by_id(id: number) {
|
|
90
|
+
const stmt = db.query("SELECT * FROM users WHERE id = ?");
|
|
91
|
+
return stmt.get(id);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Get user by email
|
|
95
|
+
export function get_user_by_email(email: string) {
|
|
96
|
+
const stmt = db.query("SELECT * FROM users WHERE email = ?");
|
|
97
|
+
return stmt.get(email);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Create user
|
|
101
|
+
export function create_user(email: string, name: string) {
|
|
102
|
+
const stmt = db.prepare(`
|
|
103
|
+
INSERT INTO users (email, name)
|
|
104
|
+
VALUES (?, ?)
|
|
105
|
+
`);
|
|
106
|
+
|
|
107
|
+
const result = stmt.run(email, name);
|
|
108
|
+
return {
|
|
109
|
+
id: result.lastInsertRowid,
|
|
110
|
+
email,
|
|
111
|
+
name,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Update user
|
|
116
|
+
export function update_user(id: number, email: string, name: string) {
|
|
117
|
+
const stmt = db.prepare(`
|
|
118
|
+
UPDATE users
|
|
119
|
+
SET email = ?, name = ?, updated_at = CURRENT_TIMESTAMP
|
|
120
|
+
WHERE id = ?
|
|
121
|
+
`);
|
|
122
|
+
|
|
123
|
+
stmt.run(email, name, id);
|
|
124
|
+
return get_user_by_id(id);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Delete user
|
|
128
|
+
export function delete_user(id: number) {
|
|
129
|
+
const stmt = db.prepare("DELETE FROM users WHERE id = ?");
|
|
130
|
+
const result = stmt.run(id);
|
|
131
|
+
return result.changes > 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Transaction example
|
|
135
|
+
export function create_user_with_profile(
|
|
136
|
+
email: string,
|
|
137
|
+
name: string,
|
|
138
|
+
bio: string
|
|
139
|
+
) {
|
|
140
|
+
const transaction = db.transaction((email, name, bio) => {
|
|
141
|
+
// Create user
|
|
142
|
+
const userStmt = db.prepare("INSERT INTO users (email, name) VALUES (?, ?)");
|
|
143
|
+
const userResult = userStmt.run(email, name);
|
|
144
|
+
const userId = userResult.lastInsertRowid;
|
|
145
|
+
|
|
146
|
+
// Create profile
|
|
147
|
+
const profileStmt = db.prepare("INSERT INTO profiles (user_id, bio) VALUES (?, ?)");
|
|
148
|
+
profileStmt.run(userId, bio);
|
|
149
|
+
|
|
150
|
+
return userId;
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
return transaction(email, name, bio);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Batch insert example
|
|
157
|
+
export function create_users_batch(users: Array<{ email: string; name: string }>) {
|
|
158
|
+
const stmt = db.prepare("INSERT INTO users (email, name) VALUES (?, ?)");
|
|
159
|
+
|
|
160
|
+
const insertMany = db.transaction((users) => {
|
|
161
|
+
for (const user of users) {
|
|
162
|
+
stmt.run(user.email, user.name);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
insertMany(users);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Type-safe query example
|
|
170
|
+
type User = {
|
|
171
|
+
id: number;
|
|
172
|
+
email: string;
|
|
173
|
+
name: string;
|
|
174
|
+
created_at: string;
|
|
175
|
+
updated_at: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function get_users_typed(): User[] {
|
|
179
|
+
return db.query<User, []>("SELECT * FROM users").all();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function get_user_by_id_typed(id: number): User | null {
|
|
183
|
+
return db.query<User, [number]>("SELECT * FROM users WHERE id = ?").get(id);
|
|
184
|
+
}
|
|
185
|
+
*/
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|