feat(database): add MySQL database support (#201)
This commit is contained in:
@@ -13,7 +13,35 @@ services:
|
||||
- JWT_SECRET=
|
||||
- INIT_TABLE=true
|
||||
- ENABLE_CACHE=true
|
||||
# MySQL Database Configuration (uncomment to use MySQL instead of SQLite)
|
||||
# - MYSQL_HOST=mysql
|
||||
# - MYSQL_PORT=3306
|
||||
# - MYSQL_USER=newsnow
|
||||
# - MYSQL_PASSWORD=your_password
|
||||
# - MYSQL_DATABASE=newsnow
|
||||
# - MYSQL_SSL=false
|
||||
# Uncomment the following lines to use MySQL database
|
||||
# depends_on:
|
||||
# - mysql
|
||||
|
||||
# Uncomment the following service to use MySQL database
|
||||
# mysql:
|
||||
# image: mysql:8.0
|
||||
# container_name: newsnow_mysql
|
||||
# restart: always
|
||||
# environment:
|
||||
# MYSQL_ROOT_PASSWORD: root_password
|
||||
# MYSQL_DATABASE: newsnow
|
||||
# MYSQL_USER: newsnow
|
||||
# MYSQL_PASSWORD: your_password
|
||||
# ports:
|
||||
# - "3306:3306"
|
||||
# volumes:
|
||||
# - mysql_data:/var/lib/mysql
|
||||
# command: --default-authentication-plugin=mysql_native_password
|
||||
|
||||
volumes:
|
||||
newsnow_data:
|
||||
name: newsnow_data
|
||||
# mysql_data:
|
||||
# name: newsnow_mysql_data
|
||||
|
||||
@@ -17,7 +17,35 @@ services:
|
||||
- JWT_SECRET=
|
||||
- INIT_TABLE=true
|
||||
- ENABLE_CACHE=true
|
||||
# MySQL Database Configuration (uncomment to use MySQL instead of SQLite)
|
||||
# - MYSQL_HOST=mysql
|
||||
# - MYSQL_PORT=3306
|
||||
# - MYSQL_USER=newsnow
|
||||
# - MYSQL_PASSWORD=your_password
|
||||
# - MYSQL_DATABASE=newsnow
|
||||
# - MYSQL_SSL=false
|
||||
# Uncomment the following lines to use MySQL database
|
||||
# depends_on:
|
||||
# - mysql
|
||||
|
||||
# Uncomment the following service to use MySQL database
|
||||
# mysql:
|
||||
# image: mysql:8.0
|
||||
# container_name: newsnow_mysql
|
||||
# restart: always
|
||||
# environment:
|
||||
# MYSQL_ROOT_PASSWORD: root_password
|
||||
# MYSQL_DATABASE: newsnow
|
||||
# MYSQL_USER: newsnow
|
||||
# MYSQL_PASSWORD: your_password
|
||||
# ports:
|
||||
# - "3306:3306"
|
||||
# volumes:
|
||||
# - mysql_data:/var/lib/mysql
|
||||
# command: --default-authentication-plugin=mysql_native_password
|
||||
|
||||
volumes:
|
||||
newsnow_data:
|
||||
name: newsnow_data
|
||||
# mysql_data:
|
||||
# name: newsnow_mysql_data
|
||||
|
||||
+9
-1
@@ -2,4 +2,12 @@ G_CLIENT_ID=
|
||||
G_CLIENT_SECRET=
|
||||
JWT_SECRET=
|
||||
INIT_TABLE=true
|
||||
ENABLE_CACHE=true
|
||||
ENABLE_CACHE=true
|
||||
# MySQL Database Configuration
|
||||
# Uncomment and configure these variables to use MySQL instead of SQLite
|
||||
# MYSQL_HOST=localhost
|
||||
# MYSQL_PORT=3306
|
||||
# MYSQL_USER=newsnow
|
||||
# MYSQL_PASSWORD=your_password
|
||||
# MYSQL_DATABASE=newsnow
|
||||
# MYSQL_SSL=false
|
||||
@@ -0,0 +1,33 @@
|
||||
-- MySQL Database Initialization Script for NewsNow
|
||||
-- Run this script to create the required database and tables
|
||||
|
||||
-- Create database if not exists
|
||||
CREATE DATABASE IF NOT EXISTS newsnow CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- Use the database
|
||||
USE newsnow;
|
||||
|
||||
-- Create cache table
|
||||
CREATE TABLE IF NOT EXISTS cache (
|
||||
id VARCHAR(255) PRIMARY KEY,
|
||||
updated BIGINT,
|
||||
data TEXT
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Create user table
|
||||
CREATE TABLE IF NOT EXISTS user (
|
||||
id VARCHAR(255) PRIMARY KEY,
|
||||
email VARCHAR(255),
|
||||
data TEXT,
|
||||
type VARCHAR(50),
|
||||
created BIGINT,
|
||||
updated BIGINT
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Create index for user table
|
||||
CREATE INDEX IF NOT EXISTS idx_user_id ON user(id);
|
||||
|
||||
-- Create MySQL user (optional - you can create this manually)
|
||||
-- CREATE USER IF NOT EXISTS 'newsnow'@'%' IDENTIFIED BY 'your_password';
|
||||
-- GRANT ALL PRIVILEGES ON newsnow.* TO 'newsnow'@'%';
|
||||
-- FLUSH PRIVILEGES;
|
||||
+50
-10
@@ -3,28 +3,68 @@ import type { NewsItem } from "@shared/types"
|
||||
import type { Database } from "db0"
|
||||
import type { CacheInfo, CacheRow } from "../types"
|
||||
|
||||
// 改进的数据库类型检测函数
|
||||
function isMySQLDatabase(): boolean {
|
||||
const hasMySQLConfig = process.env.MYSQL_HOST &&
|
||||
process.env.MYSQL_USER &&
|
||||
process.env.MYSQL_PASSWORD &&
|
||||
process.env.MYSQL_DATABASE
|
||||
|
||||
if (hasMySQLConfig) {
|
||||
console.log('🔍 检测到 MySQL 配置,使用 MySQL 数据库')
|
||||
return true
|
||||
} else {
|
||||
console.log('🔍 未检测到 MySQL 配置,使用 SQLite 数据库')
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export class Cache {
|
||||
private db
|
||||
private isMySQL: boolean
|
||||
|
||||
constructor(db: Database) {
|
||||
this.db = db
|
||||
this.isMySQL = isMySQLDatabase()
|
||||
}
|
||||
|
||||
async init() {
|
||||
await this.db.prepare(`
|
||||
CREATE TABLE IF NOT EXISTS cache (
|
||||
id TEXT PRIMARY KEY,
|
||||
updated INTEGER,
|
||||
data TEXT
|
||||
);
|
||||
`).run()
|
||||
if (this.isMySQL) {
|
||||
// MySQL syntax
|
||||
await this.db.prepare(`
|
||||
CREATE TABLE IF NOT EXISTS cache (
|
||||
id VARCHAR(255) PRIMARY KEY,
|
||||
updated BIGINT,
|
||||
data TEXT
|
||||
);
|
||||
`).run()
|
||||
} else {
|
||||
// SQLite syntax
|
||||
await this.db.prepare(`
|
||||
CREATE TABLE IF NOT EXISTS cache (
|
||||
id TEXT PRIMARY KEY,
|
||||
updated INTEGER,
|
||||
data TEXT
|
||||
);
|
||||
`).run()
|
||||
}
|
||||
logger.success(`init cache table`)
|
||||
}
|
||||
|
||||
async set(key: string, value: NewsItem[]) {
|
||||
const now = Date.now()
|
||||
await this.db.prepare(
|
||||
`INSERT OR REPLACE INTO cache (id, data, updated) VALUES (?, ?, ?)`,
|
||||
).run(key, JSON.stringify(value), now)
|
||||
|
||||
if (this.isMySQL) {
|
||||
// MySQL syntax - use ON DUPLICATE KEY UPDATE
|
||||
await this.db.prepare(
|
||||
`INSERT INTO cache (id, data, updated) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE data = VALUES(data), updated = VALUES(updated)`,
|
||||
).run(key, JSON.stringify(value), now)
|
||||
} else {
|
||||
// SQLite syntax - use INSERT OR REPLACE
|
||||
await this.db.prepare(
|
||||
`INSERT OR REPLACE INTO cache (id, data, updated) VALUES (?, ?, ?)`,
|
||||
).run(key, JSON.stringify(value), now)
|
||||
}
|
||||
logger.success(`set ${key} cache`)
|
||||
}
|
||||
|
||||
|
||||
+46
-15
@@ -1,3 +1,4 @@
|
||||
import process from "node:process"
|
||||
import type { Database } from "db0"
|
||||
import type { UserInfo } from "#/types"
|
||||
|
||||
@@ -8,28 +9,58 @@ export class UserTable {
|
||||
}
|
||||
|
||||
async init() {
|
||||
await this.db.prepare(`
|
||||
CREATE TABLE IF NOT EXISTS user (
|
||||
id TEXT PRIMARY KEY,
|
||||
email TEXT,
|
||||
data TEXT,
|
||||
type TEXT,
|
||||
created INTEGER,
|
||||
updated INTEGER
|
||||
);
|
||||
`).run()
|
||||
await this.db.prepare(`
|
||||
CREATE INDEX IF NOT EXISTS idx_user_id ON user(id);
|
||||
`).run()
|
||||
// Check if we're using MySQL by looking for MySQL environment variables
|
||||
const isMySQL = process.env.MYSQL_HOST && process.env.MYSQL_USER && process.env.MYSQL_PASSWORD && process.env.MYSQL_DATABASE
|
||||
|
||||
if (isMySQL) {
|
||||
// MySQL syntax
|
||||
await this.db.prepare(`
|
||||
CREATE TABLE IF NOT EXISTS user (
|
||||
id VARCHAR(255) PRIMARY KEY,
|
||||
email VARCHAR(255),
|
||||
data TEXT,
|
||||
type VARCHAR(50),
|
||||
created BIGINT,
|
||||
updated BIGINT
|
||||
);
|
||||
`).run()
|
||||
await this.db.prepare(`
|
||||
CREATE INDEX IF NOT EXISTS idx_user_id ON user(id);
|
||||
`).run()
|
||||
} else {
|
||||
// SQLite syntax
|
||||
await this.db.prepare(`
|
||||
CREATE TABLE IF NOT EXISTS user (
|
||||
id TEXT PRIMARY KEY,
|
||||
email TEXT,
|
||||
data TEXT,
|
||||
type TEXT,
|
||||
created INTEGER,
|
||||
updated INTEGER
|
||||
);
|
||||
`).run()
|
||||
await this.db.prepare(`
|
||||
CREATE INDEX IF NOT EXISTS idx_user_id ON user(id);
|
||||
`).run()
|
||||
}
|
||||
logger.success(`init user table`)
|
||||
}
|
||||
|
||||
async addUser(id: string, email: string, type: "github") {
|
||||
const u = await this.getUser(id)
|
||||
const now = Date.now()
|
||||
const isMySQL = process.env.MYSQL_HOST && process.env.MYSQL_USER && process.env.MYSQL_PASSWORD && process.env.MYSQL_DATABASE
|
||||
|
||||
if (!u) {
|
||||
await this.db.prepare(`INSERT INTO user (id, email, data, type, created, updated) VALUES (?, ?, ?, ?, ?, ?)`)
|
||||
.run(id, email, "", type, now, now)
|
||||
if (isMySQL) {
|
||||
// MySQL syntax - use ON DUPLICATE KEY UPDATE
|
||||
await this.db.prepare(`INSERT INTO user (id, email, data, type, created, updated) VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE email = VALUES(email), updated = VALUES(updated)`)
|
||||
.run(id, email, "", type, now, now)
|
||||
} else {
|
||||
// SQLite syntax
|
||||
await this.db.prepare(`INSERT INTO user (id, email, data, type, created, updated) VALUES (?, ?, ?, ?, ?, ?)`)
|
||||
.run(id, email, "", type, now, now)
|
||||
}
|
||||
logger.success(`add user ${id}`)
|
||||
} else if (u.email !== email && u.type !== type) {
|
||||
await this.db.prepare(`UPDATE user SET email = ?, updated = ? WHERE id = ?`).run(email, now, id)
|
||||
|
||||
Reference in New Issue
Block a user