mirror of
https://github.com/Myxelium/Bridge-Multi.git
synced 2026-04-11 14:19:38 +00:00
Add database for library
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { IpcInvokeHandlers, IpcToMainEmitHandlers } from '../src-shared/interfaces/ipc.interface.js'
|
||||
import { download } from './ipc/DownloadHandler.ipc.js'
|
||||
import { scanIssues } from './ipc/issue-scan/IssueScanHandler.ipc.js'
|
||||
import { addChart, getChartsBySearchTerm, removeAllCharts, removeChart, removeCharts } from './ipc/LibraryHandler.ipc.js'
|
||||
import { getSettings, setSettings } from './ipc/SettingsHandler.ipc.js'
|
||||
import { downloadUpdate, getCurrentVersion, getUpdateAvailable, quitAndInstall, retryUpdate } from './ipc/UpdateHandler.ipc.js'
|
||||
import { getPlatform, getThemeColors, isMaximized, maximize, minimize, openUrl, quit, restore, showFile, showFolder, showOpenDialog, toggleDevTools } from './ipc/UtilHandlers.ipc.js'
|
||||
@@ -14,6 +15,10 @@ export function getIpcInvokeHandlers(): IpcInvokeHandlers {
|
||||
isMaximized,
|
||||
showOpenDialog,
|
||||
getThemeColors,
|
||||
addChart,
|
||||
removeChart,
|
||||
removeCharts,
|
||||
getChartsBySearchTerm,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,5 +38,6 @@ export function getIpcToMainEmitHandlers(): IpcToMainEmitHandlers {
|
||||
showFile,
|
||||
showFolder,
|
||||
scanIssues,
|
||||
removeAllCharts,
|
||||
}
|
||||
}
|
||||
|
||||
18
src-electron/database/dataSource.ts
Normal file
18
src-electron/database/dataSource.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { DataSource } from 'typeorm'
|
||||
import { Chart } from './entities/Chart.js'
|
||||
import { Init1743124434920 } from './migrations/1743124434920-init.js'
|
||||
|
||||
const migrations = [Init1743124434920]
|
||||
const entities = [Chart]
|
||||
|
||||
export const dataSource = new DataSource({
|
||||
type: "sqlite",
|
||||
database: "library.sqlite",
|
||||
entities: entities,
|
||||
// Configure migrations to use a folder that contains your migration files:
|
||||
migrations: migrations,
|
||||
// Keep synchronize off when using migrations in production
|
||||
synchronize: false,
|
||||
logging: true,
|
||||
migrationsRun: true,
|
||||
})
|
||||
125
src-electron/database/databaseService.ts
Normal file
125
src-electron/database/databaseService.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
import { ChartData } from 'src-shared/interfaces/search.interface.js'
|
||||
import { dataSource } from './dataSource.js'
|
||||
import { Chart } from './entities/Chart.js'
|
||||
import { Like } from 'typeorm'
|
||||
|
||||
export class DatabaseService {
|
||||
async insertChart(chartData: ChartData): Promise<ChartData> {
|
||||
try {
|
||||
if (!dataSource.isInitialized) {
|
||||
await dataSource.initialize()
|
||||
}
|
||||
|
||||
const chartRepository = dataSource.getRepository(Chart)
|
||||
|
||||
// if one already exist dont create
|
||||
const existingChart = await chartRepository.findOneBy({ md5: chartData.md5 })
|
||||
|
||||
if (existingChart) {
|
||||
return existingChart as unknown as ChartData
|
||||
}
|
||||
|
||||
const newChart = chartRepository.create({
|
||||
name: chartData.name!,
|
||||
album: chartData.album!,
|
||||
artist: chartData.artist!,
|
||||
genre: chartData.genre!,
|
||||
year: chartData.year!,
|
||||
charter: chartData.charter!,
|
||||
md5: chartData.md5,
|
||||
hasVideoBackground: chartData.hasVideoBackground,
|
||||
})
|
||||
|
||||
return await chartRepository.save(newChart) as unknown as ChartData
|
||||
} catch (error) {
|
||||
console.error('Error inserting chart:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async removeChart(md5: string): Promise<void> {
|
||||
try {
|
||||
if (!dataSource.isInitialized) {
|
||||
await dataSource.initialize()
|
||||
}
|
||||
|
||||
const chartRepository = dataSource.getRepository(Chart)
|
||||
|
||||
await chartRepository.delete({ md5 })
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error removing chart:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async removeCharts(charts: ChartData[]): Promise<void> {
|
||||
try {
|
||||
if (!dataSource.isInitialized) {
|
||||
await dataSource.initialize()
|
||||
}
|
||||
|
||||
const chartRepository = dataSource.getRepository(Chart)
|
||||
|
||||
// delete the array of charts provided using querybulilder
|
||||
charts.forEach(async chart => {
|
||||
console.log('removing chart:', chart.name)
|
||||
await chartRepository.delete({ md5: chart.md5 })
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error removing charts:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async getChartsBySearchTerm(searchTerm?: string): Promise<ChartData[]> {
|
||||
try {
|
||||
if (!dataSource.isInitialized) {
|
||||
await dataSource.initialize()
|
||||
}
|
||||
|
||||
const chartRepository = dataSource.getRepository(Chart)
|
||||
|
||||
let charts: Chart[]
|
||||
|
||||
if (searchTerm) {
|
||||
const likeSearchTerm = `%${searchTerm}%`
|
||||
charts = await chartRepository.find({
|
||||
where: [
|
||||
{ name: Like(likeSearchTerm) },
|
||||
{ album: Like(likeSearchTerm) },
|
||||
{ artist: Like(likeSearchTerm) },
|
||||
{ genre: Like(likeSearchTerm) },
|
||||
{ year: Like(likeSearchTerm) },
|
||||
{ charter: Like(likeSearchTerm) },
|
||||
],
|
||||
})
|
||||
} else {
|
||||
charts = await chartRepository.find()
|
||||
}
|
||||
|
||||
return charts as unknown as ChartData[]
|
||||
} catch (error) {
|
||||
console.error('Error fetching charts by search term:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async removeAllCharts(): Promise<void> {
|
||||
try {
|
||||
if (!dataSource.isInitialized) {
|
||||
await dataSource.initialize()
|
||||
}
|
||||
|
||||
const chartRepository = dataSource.getRepository(Chart)
|
||||
|
||||
await chartRepository.clear()
|
||||
} catch (error) {
|
||||
console.error('Error removing all charts:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const databaseService = new DatabaseService()
|
||||
31
src-electron/database/entities/Chart.ts
Normal file
31
src-electron/database/entities/Chart.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'
|
||||
|
||||
@Entity()
|
||||
export class Chart {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string
|
||||
|
||||
@Column()
|
||||
md5: string
|
||||
|
||||
@Column()
|
||||
hasVideoBackground: boolean
|
||||
|
||||
@Column()
|
||||
charter: string
|
||||
|
||||
@Column()
|
||||
name: string
|
||||
|
||||
@Column()
|
||||
artist: string
|
||||
|
||||
@Column()
|
||||
album: string
|
||||
|
||||
@Column()
|
||||
genre: string
|
||||
|
||||
@Column()
|
||||
year: string
|
||||
}
|
||||
14
src-electron/database/migrations/1743124434920-init.ts
Normal file
14
src-electron/database/migrations/1743124434920-init.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class Init1743124434920 implements MigrationInterface {
|
||||
name = 'Init1743124434920'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`CREATE TABLE "chart" ("id" varchar PRIMARY KEY NOT NULL, "md5" varchar NOT NULL, "hasVideoBackground" boolean NOT NULL, "charter" varchar NOT NULL, "name" varchar NOT NULL, "artist" varchar NOT NULL, "album" varchar NOT NULL, "genre" varchar NOT NULL, "year" varchar NOT NULL)`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`DROP TABLE "chart"`);
|
||||
}
|
||||
|
||||
}
|
||||
10
src-electron/database/readme.md
Normal file
10
src-electron/database/readme.md
Normal file
@@ -0,0 +1,10 @@
|
||||
## Migrations
|
||||
In order to create a new migration, there is a some steps to go through.
|
||||
|
||||
1. Run ``npm run migration:add --name <migration name>`` This currently work for Windows machines. If using Linux or Mac run this instead ``npx typeorm-ts-node-esm migration:generate ./src-electron/database/migrations/<migration name> -d ./src-electron/database/dataSource.ts``
|
||||
|
||||
2. Go to ``./src-electron/database/dataSource.ts`` and add the newly
|
||||
generated migration to the migrations array and entity variables. In that way it will automatically apply the latest changes to the database on startup.
|
||||
|
||||
## The database
|
||||
A Sqlite database file is automatically created on startup named Library, it will be placed in the same directory as the executable.
|
||||
47
src-electron/ipc/LibraryHandler.ipc.ts
Normal file
47
src-electron/ipc/LibraryHandler.ipc.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { databaseService } from '../database/databaseService.js'
|
||||
import { ChartData } from 'src-shared/interfaces/search.interface.js'
|
||||
|
||||
export async function addChart(chartData: ChartData): Promise<ChartData> {
|
||||
try {
|
||||
return await databaseService.insertChart(chartData)
|
||||
} catch (error) {
|
||||
console.error('Error in addChartHandler:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export async function removeChart(md5: string): Promise<void> {
|
||||
try {
|
||||
await databaseService.removeChart(md5)
|
||||
} catch (error) {
|
||||
console.error('Error in removeChartHandler:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export async function removeCharts(charts: ChartData[]): Promise<void> {
|
||||
try {
|
||||
await databaseService.removeCharts(charts)
|
||||
} catch (error) {
|
||||
console.error('Error in removeChartsHandler:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export async function removeAllCharts(): Promise<void> {
|
||||
try {
|
||||
await databaseService.removeAllCharts()
|
||||
} catch (error) {
|
||||
console.error('Error in removeAllChartsHandler:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export async function getChartsBySearchTerm(searchTerm?: string): Promise<ChartData[]> {
|
||||
try {
|
||||
return await databaseService.getChartsBySearchTerm(searchTerm)
|
||||
} catch (error) {
|
||||
console.error('Error in getChartsHandler:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,13 @@ import electronUnhandled from 'electron-unhandled'
|
||||
import windowStateKeeper from 'electron-window-state'
|
||||
import * as path from 'path'
|
||||
import * as url from 'url'
|
||||
|
||||
import "reflect-metadata"
|
||||
import { IpcFromMainEmitEvents } from '../src-shared/interfaces/ipc.interface.js'
|
||||
import { dataPath } from '../src-shared/Paths.js'
|
||||
import { settings } from './ipc/SettingsHandler.ipc.js'
|
||||
import { retryUpdate } from './ipc/UpdateHandler.ipc.js'
|
||||
import { getIpcInvokeHandlers, getIpcToMainEmitHandlers } from './IpcHandler.js'
|
||||
import { dataSource } from './database/dataSource.js'
|
||||
|
||||
electronUnhandled({ showDialog: true, logger: err => console.log('Error: Unhandled Rejection:', err) })
|
||||
|
||||
@@ -26,6 +27,14 @@ app.on('ready', async () => {
|
||||
if (!isDevBuild) {
|
||||
retryUpdate()
|
||||
}
|
||||
|
||||
// Initialize the database
|
||||
dataSource.initialize().then(() => {
|
||||
console.log('Database initialized')
|
||||
}
|
||||
).catch(error => {
|
||||
console.error('Error initializing database:', error)
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,6 +25,10 @@ const electronApi: ContextBridgeApi = {
|
||||
isMaximized: getInvoker('isMaximized'),
|
||||
showOpenDialog: getInvoker('showOpenDialog'),
|
||||
getThemeColors: getInvoker('getThemeColors'),
|
||||
addChart: getInvoker('addChart'),
|
||||
removeChart: getInvoker('removeChart'),
|
||||
removeCharts: getInvoker('removeCharts'),
|
||||
getChartsBySearchTerm: getInvoker('getChartsBySearchTerm'),
|
||||
},
|
||||
emit: {
|
||||
download: getEmitter('download'),
|
||||
@@ -41,6 +45,7 @@ const electronApi: ContextBridgeApi = {
|
||||
showFolder: getEmitter('showFolder'),
|
||||
showFile: getEmitter('showFile'),
|
||||
scanIssues: getEmitter('scanIssues'),
|
||||
removeAllCharts: getEmitter('removeAllCharts'),
|
||||
},
|
||||
on: {
|
||||
errorLog: getListenerAdder('errorLog'),
|
||||
|
||||
Reference in New Issue
Block a user