API, UI, Linux/MikroTik agents, IP lists, политики, stats, CI и интеграция с auth-portal/EvoBGP. Co-authored-by: Cursor <cursoragent@cursor.com>
74 lines
2.1 KiB
TypeScript
74 lines
2.1 KiB
TypeScript
import { dirname, join } from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
import { readFileSync, readdirSync, mkdirSync } from 'node:fs'
|
|
import Database from 'better-sqlite3'
|
|
import { drizzle } from 'drizzle-orm/better-sqlite3'
|
|
import { schema } from './schema.js'
|
|
|
|
export type Sqlite = Database.Database
|
|
export type Db = ReturnType<typeof drizzle<typeof schema>>
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
|
|
export function resolveDatabasePath(databaseUrl: string): string {
|
|
const url = databaseUrl.startsWith('sqlite:')
|
|
? databaseUrl.slice('sqlite:'.length)
|
|
: databaseUrl
|
|
return url
|
|
}
|
|
|
|
export function createDb(databaseUrl: string): { db: Db; sqlite: Sqlite } {
|
|
const path = resolveDatabasePath(databaseUrl)
|
|
const dir = dirname(path)
|
|
if (dir && dir !== '.') {
|
|
try {
|
|
mkdirSync(dir, { recursive: true })
|
|
} catch {
|
|
/* exists */
|
|
}
|
|
}
|
|
const sqlite = new Database(path)
|
|
sqlite.pragma('journal_mode = WAL')
|
|
sqlite.pragma('synchronous = NORMAL')
|
|
sqlite.pragma('foreign_keys = ON')
|
|
const db = drizzle(sqlite, { schema })
|
|
return { db, sqlite }
|
|
}
|
|
|
|
export function createMemoryDb(): { db: Db; sqlite: Sqlite } {
|
|
const sqlite = new Database(':memory:')
|
|
sqlite.pragma('foreign_keys = ON')
|
|
const db = drizzle(sqlite, { schema })
|
|
return { db, sqlite }
|
|
}
|
|
|
|
export function runMigrations(sqlite: Sqlite): void {
|
|
const migrationsDir = join(__dirname, '..', 'migrations')
|
|
const files = readdirSync(migrationsDir)
|
|
.filter((f) => f.endsWith('.sql'))
|
|
.sort()
|
|
|
|
sqlite.exec(
|
|
`CREATE TABLE IF NOT EXISTS _migrations (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL UNIQUE,
|
|
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
)`,
|
|
)
|
|
|
|
for (const file of files) {
|
|
const applied = sqlite
|
|
.prepare('SELECT 1 FROM _migrations WHERE name = ?')
|
|
.get(file)
|
|
if (applied) continue
|
|
|
|
const sql = readFileSync(join(migrationsDir, file), 'utf-8')
|
|
sqlite.exec(sql)
|
|
sqlite.prepare('INSERT INTO _migrations (name) VALUES (?)').run(file)
|
|
}
|
|
}
|
|
|
|
export function healthCheck(sqlite: Sqlite): void {
|
|
sqlite.prepare('SELECT 1').get()
|
|
}
|