initial commit
This commit is contained in:
57
src/lib/database/config.ts
Normal file
57
src/lib/database/config.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import { DataSource, DataSourceOptions } from 'typeorm';
|
||||
import { User } from './entities/User';
|
||||
import { Post } from './entities/Post';
|
||||
import path from 'path';
|
||||
|
||||
// Default configuration for SQLite (development/testing)
|
||||
const sqliteConfig: DataSourceOptions = {
|
||||
type: 'sqlite',
|
||||
database: path.join(process.cwd(), 'data', 'database.sqlite'),
|
||||
entities: [User, Post],
|
||||
synchronize: true, // Set to false in production
|
||||
logging: process.env.NODE_ENV === 'development',
|
||||
};
|
||||
|
||||
// MySQL configuration
|
||||
const mysqlConfig: DataSourceOptions = {
|
||||
type: 'mysql',
|
||||
host: process.env.DB_HOST || 'localhost',
|
||||
port: parseInt(process.env.DB_PORT || '3306'),
|
||||
username: process.env.DB_USERNAME || 'root',
|
||||
password: process.env.DB_PASSWORD || '',
|
||||
database: process.env.DB_DATABASE || 'kantancms',
|
||||
entities: [User, Post],
|
||||
synchronize: false, // Always false in production
|
||||
logging: process.env.NODE_ENV === 'development',
|
||||
};
|
||||
|
||||
// PostgreSQL configuration
|
||||
const postgresConfig: DataSourceOptions = {
|
||||
type: 'postgres',
|
||||
host: process.env.DB_HOST || 'localhost',
|
||||
port: parseInt(process.env.DB_PORT || '5432'),
|
||||
username: process.env.DB_USERNAME || 'postgres',
|
||||
password: process.env.DB_PASSWORD || '',
|
||||
database: process.env.DB_DATABASE || 'kantancms',
|
||||
entities: [User, Post],
|
||||
synchronize: false, // Always false in production
|
||||
logging: process.env.NODE_ENV === 'development',
|
||||
};
|
||||
|
||||
// Select the database configuration based on environment variable
|
||||
const getConfig = (): DataSourceOptions => {
|
||||
const dbType = process.env.DB_TYPE || 'sqlite';
|
||||
|
||||
switch (dbType) {
|
||||
case 'mysql':
|
||||
return mysqlConfig;
|
||||
case 'postgres':
|
||||
return postgresConfig;
|
||||
case 'sqlite':
|
||||
default:
|
||||
return sqliteConfig;
|
||||
}
|
||||
};
|
||||
|
||||
// Create and export the DataSource
|
||||
export const AppDataSource = new DataSource(getConfig());
|
||||
35
src/lib/database/entities/Post.ts
Normal file
35
src/lib/database/entities/Post.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from 'typeorm';
|
||||
// Forward reference to User to avoid circular dependency
|
||||
import type { User } from './User';
|
||||
|
||||
@Entity('posts')
|
||||
export class Post {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
parentId: string;
|
||||
|
||||
@Column()
|
||||
userId: string;
|
||||
|
||||
@Column()
|
||||
title: string;
|
||||
|
||||
@Column('text')
|
||||
content: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn()
|
||||
modifiedAt: Date;
|
||||
|
||||
@ManyToOne(() => Post, post => post.id, { nullable: true })
|
||||
@JoinColumn({ name: 'parentId' })
|
||||
parent: Post;
|
||||
|
||||
@ManyToOne('User', 'posts')
|
||||
@JoinColumn({ name: 'userId' })
|
||||
user: User;
|
||||
}
|
||||
41
src/lib/database/entities/User.ts
Normal file
41
src/lib/database/entities/User.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, OneToMany } from 'typeorm';
|
||||
// Forward reference to Post to avoid circular dependency
|
||||
import type { Post } from './Post';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
|
||||
@Entity('users')
|
||||
export class User {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ unique: true })
|
||||
username: string;
|
||||
|
||||
@Column()
|
||||
password: string;
|
||||
|
||||
@Column({ nullable: true, type: 'varchar', default: null })
|
||||
avatar: string | null;
|
||||
|
||||
@Column({ type: 'varchar', default: 'system' })
|
||||
theme: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn()
|
||||
modifiedAt: Date;
|
||||
|
||||
@OneToMany('Post', 'user')
|
||||
posts: Post[];
|
||||
|
||||
// Method to hash password before saving
|
||||
async hashPassword() {
|
||||
this.password = await bcrypt.hash(this.password, 10);
|
||||
}
|
||||
|
||||
// Method to validate password
|
||||
async validatePassword(password: string): Promise<boolean> {
|
||||
return bcrypt.compare(password, this.password);
|
||||
}
|
||||
}
|
||||
36
src/lib/database/index.ts
Normal file
36
src/lib/database/index.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import 'reflect-metadata';
|
||||
import { AppDataSource } from './config';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
// Ensure data directory exists for SQLite
|
||||
const dataDir = path.join(process.cwd(), 'data');
|
||||
if (!fs.existsSync(dataDir)) {
|
||||
fs.mkdirSync(dataDir, { recursive: true });
|
||||
}
|
||||
|
||||
// Initialize database connection
|
||||
export const initializeDatabase = async () => {
|
||||
try {
|
||||
if (!AppDataSource.isInitialized) {
|
||||
await AppDataSource.initialize();
|
||||
console.log('Database connection established successfully');
|
||||
}
|
||||
return AppDataSource;
|
||||
} catch (error) {
|
||||
console.error('Error during database initialization:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Get the initialized data source
|
||||
export const getDataSource = async () => {
|
||||
if (!AppDataSource.isInitialized) {
|
||||
await initializeDatabase();
|
||||
}
|
||||
return AppDataSource;
|
||||
};
|
||||
|
||||
// Export entities - Post must be exported after User to resolve circular dependency
|
||||
export * from './entities/User';
|
||||
export * from './entities/Post';
|
||||
Reference in New Issue
Block a user