mirror of
https://github.com/woodchen-ink/aimodels-prices.git
synced 2025-07-18 05:32:00 +08:00
Migrate from SQLite to MySQL: Update database configuration and schema
This commit is contained in:
parent
8d198e45af
commit
a2932ecf6b
26
.env.example
26
.env.example
@ -1,8 +1,18 @@
|
|||||||
PORT=8080
|
# MySQL数据库配置
|
||||||
GIN_MODE=debug
|
DB_HOST=localhost # 数据库主机地址
|
||||||
OAUTH_CLIENT_ID=your_client_id_here
|
DB_PORT=3306 # 数据库端口
|
||||||
OAUTH_CLIENT_SECRET=your_client_secret_here
|
DB_USER=root # 数据库用户名
|
||||||
OAUTH_REDIRECT_URI=https://aimodels-prices.q58.club/api/auth/callback
|
DB_PASSWORD=your_password # 数据库密码
|
||||||
OAUTH_AUTHORIZE_URL=https://connect.q58.club/oauth/authorize
|
DB_NAME=aimodels # 数据库名称
|
||||||
OAUTH_TOKEN_URL=https://connect.q58.club/api/oauth/access_token
|
|
||||||
OAUTH_USER_URL=https://connect.q58.club/api/oauth/user
|
# 服务器配置
|
||||||
|
PORT=8080 # 服务器监听端口
|
||||||
|
|
||||||
|
# OAuth配置(如果需要)
|
||||||
|
OAUTH_CLIENT_ID=your_client_id
|
||||||
|
OAUTH_CLIENT_SECRET=your_client_secret
|
||||||
|
OAUTH_REDIRECT_URI=http://localhost:8080/api/auth/callback
|
||||||
|
OAUTH_AUTHORIZE_URL=https://example.com/oauth/authorize
|
||||||
|
|
||||||
|
# 其他配置
|
||||||
|
GIN_MODE=debug # Gin运行模式:debug或release
|
238
backend/cmd/migrate/main.go
Normal file
238
backend/cmd/migrate/main.go
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"aimodels-prices/config"
|
||||||
|
"aimodels-prices/database"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// 加载配置
|
||||||
|
cfg, err := config.LoadConfig()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to load config: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查SQLite数据库文件是否存在
|
||||||
|
if _, err := os.Stat(cfg.SQLitePath); os.IsNotExist(err) {
|
||||||
|
log.Printf("SQLite database file not found at %s, skipping migration", cfg.SQLitePath)
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 连接SQLite数据库
|
||||||
|
sqliteDB, err := database.InitSQLiteDB(cfg.SQLitePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to connect to SQLite database: %v", err)
|
||||||
|
}
|
||||||
|
defer sqliteDB.Close()
|
||||||
|
|
||||||
|
// 初始化MySQL数据库
|
||||||
|
if err := database.InitDB(cfg); err != nil {
|
||||||
|
log.Fatalf("Failed to initialize MySQL database: %v", err)
|
||||||
|
}
|
||||||
|
defer database.DB.Close()
|
||||||
|
|
||||||
|
// 开始迁移数据
|
||||||
|
if err := migrateData(sqliteDB, database.DB); err != nil {
|
||||||
|
log.Fatalf("Failed to migrate data: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Data migration completed successfully!")
|
||||||
|
}
|
||||||
|
|
||||||
|
func migrateData(sqliteDB *sql.DB, mysqlDB *sql.DB) error {
|
||||||
|
// 迁移用户数据
|
||||||
|
if err := migrateUsers(sqliteDB, mysqlDB); err != nil {
|
||||||
|
return fmt.Errorf("failed to migrate users: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 迁移会话数据
|
||||||
|
if err := migrateSessions(sqliteDB, mysqlDB); err != nil {
|
||||||
|
return fmt.Errorf("failed to migrate sessions: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 迁移提供商数据
|
||||||
|
if err := migrateProviders(sqliteDB, mysqlDB); err != nil {
|
||||||
|
return fmt.Errorf("failed to migrate providers: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 迁移价格数据
|
||||||
|
if err := migratePrices(sqliteDB, mysqlDB); err != nil {
|
||||||
|
return fmt.Errorf("failed to migrate prices: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func migrateUsers(sqliteDB *sql.DB, mysqlDB *sql.DB) error {
|
||||||
|
rows, err := sqliteDB.Query("SELECT id, username, email, role, created_at, updated_at, deleted_at FROM user")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var (
|
||||||
|
id uint
|
||||||
|
username string
|
||||||
|
email string
|
||||||
|
role string
|
||||||
|
createdAt string
|
||||||
|
updatedAt string
|
||||||
|
deletedAt sql.NullString
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := rows.Scan(&id, &username, &email, &role, &createdAt, &updatedAt, &deletedAt); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = mysqlDB.Exec(
|
||||||
|
"INSERT INTO user (id, username, email, role, created_at, updated_at, deleted_at) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||||
|
id, username, email, role, createdAt, updatedAt, deletedAt.String,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func migrateSessions(sqliteDB *sql.DB, mysqlDB *sql.DB) error {
|
||||||
|
rows, err := sqliteDB.Query("SELECT id, user_id, expires_at, created_at, updated_at, deleted_at FROM session")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var (
|
||||||
|
id string
|
||||||
|
userID uint
|
||||||
|
expiresAt string
|
||||||
|
createdAt string
|
||||||
|
updatedAt string
|
||||||
|
deletedAt sql.NullString
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := rows.Scan(&id, &userID, &expiresAt, &createdAt, &updatedAt, &deletedAt); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = mysqlDB.Exec(
|
||||||
|
"INSERT INTO session (id, user_id, expires_at, created_at, updated_at, deleted_at) VALUES (?, ?, ?, ?, ?, ?)",
|
||||||
|
id, userID, expiresAt, createdAt, updatedAt, deletedAt.String,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func migrateProviders(sqliteDB *sql.DB, mysqlDB *sql.DB) error {
|
||||||
|
rows, err := sqliteDB.Query("SELECT id, name, icon, created_at, updated_at, created_by FROM provider")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var (
|
||||||
|
id uint
|
||||||
|
name string
|
||||||
|
icon sql.NullString
|
||||||
|
createdAt string
|
||||||
|
updatedAt string
|
||||||
|
createdBy string
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := rows.Scan(&id, &name, &icon, &createdAt, &updatedAt, &createdBy); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = mysqlDB.Exec(
|
||||||
|
"INSERT INTO provider (id, name, icon, created_at, updated_at, created_by) VALUES (?, ?, ?, ?, ?, ?)",
|
||||||
|
id, name, icon.String, createdAt, updatedAt, createdBy,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func migratePrices(sqliteDB *sql.DB, mysqlDB *sql.DB) error {
|
||||||
|
rows, err := sqliteDB.Query(`
|
||||||
|
SELECT id, model, model_type, billing_type, channel_type, currency,
|
||||||
|
input_price, output_price, price_source, status, created_at, updated_at,
|
||||||
|
created_by, temp_model, temp_model_type, temp_billing_type, temp_channel_type,
|
||||||
|
temp_currency, temp_input_price, temp_output_price, temp_price_source, updated_by
|
||||||
|
FROM price
|
||||||
|
`)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var (
|
||||||
|
id uint
|
||||||
|
model string
|
||||||
|
modelType string
|
||||||
|
billingType string
|
||||||
|
channelType string
|
||||||
|
currency string
|
||||||
|
inputPrice float64
|
||||||
|
outputPrice float64
|
||||||
|
priceSource string
|
||||||
|
status string
|
||||||
|
createdAt string
|
||||||
|
updatedAt string
|
||||||
|
createdBy string
|
||||||
|
tempModel sql.NullString
|
||||||
|
tempModelType sql.NullString
|
||||||
|
tempBillingType sql.NullString
|
||||||
|
tempChannelType sql.NullString
|
||||||
|
tempCurrency sql.NullString
|
||||||
|
tempInputPrice sql.NullFloat64
|
||||||
|
tempOutputPrice sql.NullFloat64
|
||||||
|
tempPriceSource sql.NullString
|
||||||
|
updatedBy sql.NullString
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := rows.Scan(
|
||||||
|
&id, &model, &modelType, &billingType, &channelType, ¤cy,
|
||||||
|
&inputPrice, &outputPrice, &priceSource, &status, &createdAt, &updatedAt,
|
||||||
|
&createdBy, &tempModel, &tempModelType, &tempBillingType, &tempChannelType,
|
||||||
|
&tempCurrency, &tempInputPrice, &tempOutputPrice, &tempPriceSource, &updatedBy,
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = mysqlDB.Exec(`
|
||||||
|
INSERT INTO price (
|
||||||
|
id, model, model_type, billing_type, channel_type, currency,
|
||||||
|
input_price, output_price, price_source, status, created_at, updated_at,
|
||||||
|
created_by, temp_model, temp_model_type, temp_billing_type, temp_channel_type,
|
||||||
|
temp_currency, temp_input_price, temp_output_price, temp_price_source, updated_by
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
`,
|
||||||
|
id, model, modelType, billingType, channelType, currency,
|
||||||
|
inputPrice, outputPrice, priceSource, status, createdAt, updatedAt,
|
||||||
|
createdBy, tempModel.String, tempModelType.String, tempBillingType.String, tempChannelType.String,
|
||||||
|
tempCurrency.String, tempInputPrice.Float64, tempOutputPrice.Float64, tempPriceSource.String, updatedBy.String,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows.Err()
|
||||||
|
}
|
@ -9,8 +9,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
DBPath string
|
// MySQL配置
|
||||||
|
DBHost string
|
||||||
|
DBPort string
|
||||||
|
DBUser string
|
||||||
|
DBPassword string
|
||||||
|
DBName string
|
||||||
|
|
||||||
|
// 其他配置
|
||||||
ServerPort string
|
ServerPort string
|
||||||
|
|
||||||
|
// SQLite配置(用于数据迁移)
|
||||||
|
SQLitePath string
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadConfig() (*Config, error) {
|
func LoadConfig() (*Config, error) {
|
||||||
@ -31,8 +41,18 @@ func LoadConfig() (*Config, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
config := &Config{
|
config := &Config{
|
||||||
DBPath: filepath.Join(dbDir, "aimodels.db"),
|
// MySQL配置
|
||||||
|
DBHost: getEnv("DB_HOST", "localhost"),
|
||||||
|
DBPort: getEnv("DB_PORT", "3306"),
|
||||||
|
DBUser: getEnv("DB_USER", "root"),
|
||||||
|
DBPassword: getEnv("DB_PASSWORD", ""),
|
||||||
|
DBName: getEnv("DB_NAME", "aimodels"),
|
||||||
|
|
||||||
|
// 其他配置
|
||||||
ServerPort: getEnv("PORT", "8080"),
|
ServerPort: getEnv("PORT", "8080"),
|
||||||
|
|
||||||
|
// SQLite路径(用于数据迁移)
|
||||||
|
SQLitePath: filepath.Join(dbDir, "aimodels.db"),
|
||||||
}
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
|
@ -2,10 +2,13 @@ package database
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
_ "modernc.org/sqlite"
|
_ "modernc.org/sqlite"
|
||||||
|
|
||||||
|
"aimodels-prices/config"
|
||||||
"aimodels-prices/models"
|
"aimodels-prices/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -13,16 +16,27 @@ import (
|
|||||||
var DB *sql.DB
|
var DB *sql.DB
|
||||||
|
|
||||||
// InitDB 初始化数据库连接
|
// InitDB 初始化数据库连接
|
||||||
func InitDB(dbPath string) error {
|
func InitDB(cfg *config.Config) error {
|
||||||
var err error
|
var err error
|
||||||
DB, err = sql.Open("sqlite", dbPath)
|
|
||||||
|
// 构建MySQL DSN
|
||||||
|
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
||||||
|
cfg.DBUser,
|
||||||
|
cfg.DBPassword,
|
||||||
|
cfg.DBHost,
|
||||||
|
cfg.DBPort,
|
||||||
|
cfg.DBName,
|
||||||
|
)
|
||||||
|
|
||||||
|
// 连接MySQL
|
||||||
|
DB, err = sql.Open("mysql", dsn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to connect to MySQL: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 测试连接
|
// 测试连接
|
||||||
if err = DB.Ping(); err != nil {
|
if err = DB.Ping(); err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to ping MySQL: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置连接池参数
|
// 设置连接池参数
|
||||||
@ -31,12 +45,26 @@ func InitDB(dbPath string) error {
|
|||||||
|
|
||||||
// 创建表结构
|
// 创建表结构
|
||||||
if err = createTables(); err != nil {
|
if err = createTables(); err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to create tables: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InitSQLiteDB 初始化SQLite数据库连接(用于数据迁移)
|
||||||
|
func InitSQLiteDB(dbPath string) (*sql.DB, error) {
|
||||||
|
db, err := sql.Open("sqlite", dbPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to connect to SQLite: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = db.Ping(); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to ping SQLite: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return db, nil
|
||||||
|
}
|
||||||
|
|
||||||
// createTables 创建数据库表
|
// createTables 创建数据库表
|
||||||
func createTables() error {
|
func createTables() error {
|
||||||
// 创建用户表
|
// 创建用户表
|
||||||
|
@ -4,6 +4,7 @@ go 1.21
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gin-gonic/gin v1.9.1
|
github.com/gin-gonic/gin v1.9.1
|
||||||
|
github.com/go-sql-driver/mysql v1.7.1
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
modernc.org/sqlite v1.28.0
|
modernc.org/sqlite v1.28.0
|
||||||
)
|
)
|
||||||
|
@ -23,6 +23,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
|
|||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
||||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||||
|
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
||||||
|
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
@ -20,7 +20,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 初始化数据库
|
// 初始化数据库
|
||||||
if err := database.InitDB(cfg.DBPath); err != nil {
|
if err := database.InitDB(cfg); err != nil {
|
||||||
log.Fatalf("Failed to initialize database: %v", err)
|
log.Fatalf("Failed to initialize database: %v", err)
|
||||||
}
|
}
|
||||||
defer database.DB.Close()
|
defer database.DB.Close()
|
||||||
|
@ -34,28 +34,28 @@ type Price struct {
|
|||||||
func CreatePriceTableSQL() string {
|
func CreatePriceTableSQL() string {
|
||||||
return `
|
return `
|
||||||
CREATE TABLE IF NOT EXISTS price (
|
CREATE TABLE IF NOT EXISTS price (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||||
model TEXT NOT NULL,
|
model VARCHAR(255) NOT NULL,
|
||||||
model_type TEXT NOT NULL,
|
model_type VARCHAR(50) NOT NULL,
|
||||||
billing_type TEXT NOT NULL,
|
billing_type VARCHAR(50) NOT NULL,
|
||||||
channel_type TEXT NOT NULL,
|
channel_type VARCHAR(50) NOT NULL,
|
||||||
currency TEXT NOT NULL,
|
currency VARCHAR(10) NOT NULL,
|
||||||
input_price REAL NOT NULL,
|
input_price DECIMAL(10,6) NOT NULL,
|
||||||
output_price REAL NOT NULL,
|
output_price DECIMAL(10,6) NOT NULL,
|
||||||
price_source TEXT NOT NULL,
|
price_source VARCHAR(255) NOT NULL,
|
||||||
status TEXT NOT NULL DEFAULT 'pending',
|
status VARCHAR(50) NOT NULL DEFAULT 'pending',
|
||||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
created_by TEXT NOT NULL,
|
created_by VARCHAR(255) NOT NULL,
|
||||||
temp_model TEXT,
|
temp_model VARCHAR(255),
|
||||||
temp_model_type TEXT,
|
temp_model_type VARCHAR(50),
|
||||||
temp_billing_type TEXT,
|
temp_billing_type VARCHAR(50),
|
||||||
temp_channel_type TEXT,
|
temp_channel_type VARCHAR(50),
|
||||||
temp_currency TEXT,
|
temp_currency VARCHAR(10),
|
||||||
temp_input_price REAL,
|
temp_input_price DECIMAL(10,6),
|
||||||
temp_output_price REAL,
|
temp_output_price DECIMAL(10,6),
|
||||||
temp_price_source TEXT,
|
temp_price_source VARCHAR(255),
|
||||||
updated_by TEXT,
|
updated_by VARCHAR(255),
|
||||||
FOREIGN KEY (channel_type) REFERENCES provider(id)
|
FOREIGN KEY (channel_type) REFERENCES provider(id)
|
||||||
)`
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,11 @@ type Provider struct {
|
|||||||
func CreateProviderTableSQL() string {
|
func CreateProviderTableSQL() string {
|
||||||
return `
|
return `
|
||||||
CREATE TABLE IF NOT EXISTS provider (
|
CREATE TABLE IF NOT EXISTS provider (
|
||||||
id INTEGER PRIMARY KEY,
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||||
name TEXT NOT NULL,
|
name VARCHAR(255) NOT NULL,
|
||||||
icon TEXT,
|
icon VARCHAR(1024),
|
||||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
created_by TEXT NOT NULL
|
created_by VARCHAR(255) NOT NULL
|
||||||
)`
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`
|
||||||
}
|
}
|
||||||
|
@ -24,32 +24,32 @@ type Session struct {
|
|||||||
DeletedAt *time.Time `json:"deleted_at,omitempty"`
|
DeletedAt *time.Time `json:"deleted_at,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateTableSQL 返回创建用户表的 SQL
|
// CreateUserTableSQL 返回创建用户表的 SQL
|
||||||
func CreateUserTableSQL() string {
|
func CreateUserTableSQL() string {
|
||||||
return `
|
return `
|
||||||
CREATE TABLE IF NOT EXISTS user (
|
CREATE TABLE IF NOT EXISTS user (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||||
username TEXT UNIQUE NOT NULL,
|
username VARCHAR(255) UNIQUE NOT NULL,
|
||||||
email TEXT UNIQUE NOT NULL,
|
email VARCHAR(255) UNIQUE NOT NULL,
|
||||||
role TEXT NOT NULL DEFAULT 'user',
|
role VARCHAR(50) NOT NULL DEFAULT 'user',
|
||||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
deleted_at DATETIME
|
deleted_at TIMESTAMP NULL
|
||||||
)`
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateSessionTableSQL 返回创建会话表的 SQL
|
// CreateSessionTableSQL 返回创建会话表的 SQL
|
||||||
func CreateSessionTableSQL() string {
|
func CreateSessionTableSQL() string {
|
||||||
return `
|
return `
|
||||||
CREATE TABLE IF NOT EXISTS session (
|
CREATE TABLE IF NOT EXISTS session (
|
||||||
id TEXT PRIMARY KEY,
|
id VARCHAR(255) PRIMARY KEY,
|
||||||
user_id INTEGER NOT NULL,
|
user_id BIGINT UNSIGNED NOT NULL,
|
||||||
expires_at DATETIME NOT NULL,
|
expires_at TIMESTAMP NOT NULL,
|
||||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
deleted_at DATETIME,
|
deleted_at TIMESTAMP NULL,
|
||||||
FOREIGN KEY (user_id) REFERENCES user(id)
|
FOREIGN KEY (user_id) REFERENCES user(id)
|
||||||
)`
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUser 获取会话关联的用户
|
// GetUser 获取会话关联的用户
|
||||||
|
19
scripts/build.sh
Normal file
19
scripts/build.sh
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 设置Go环境变量
|
||||||
|
export CGO_ENABLED=0
|
||||||
|
export GOOS=linux
|
||||||
|
|
||||||
|
# 编译 AMD64 版本
|
||||||
|
echo "Building AMD64 version..."
|
||||||
|
export GOARCH=amd64
|
||||||
|
go build -o backend/main-amd64 backend/main.go
|
||||||
|
go build -o backend/migrate-amd64 backend/cmd/migrate/main.go
|
||||||
|
|
||||||
|
# 编译 ARM64 版本
|
||||||
|
echo "Building ARM64 version..."
|
||||||
|
export GOARCH=arm64
|
||||||
|
go build -o backend/main-arm64 backend/main.go
|
||||||
|
go build -o backend/migrate-arm64 backend/cmd/migrate/main.go
|
||||||
|
|
||||||
|
echo "Build completed!"
|
@ -5,7 +5,9 @@ echo "执行数据库迁移..."
|
|||||||
./migrate
|
./migrate
|
||||||
|
|
||||||
# 启动后端服务
|
# 启动后端服务
|
||||||
|
echo "启动后端服务..."
|
||||||
./main &
|
./main &
|
||||||
|
|
||||||
# 启动 nginx
|
# 启动 nginx
|
||||||
|
echo "启动 Nginx..."
|
||||||
nginx -g 'daemon off;'
|
nginx -g 'daemon off;'
|
Loading…
x
Reference in New Issue
Block a user