databaseInit.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. const { executeQuery, executeNonQuery } = require('../config/database');
  2. const { logger } = require('./logger');
  3. class DatabaseInitializer {
  4. constructor() {
  5. this.initialized = false;
  6. }
  7. async initialize() {
  8. if (this.initialized) {
  9. logger.info('Database already initialized');
  10. return;
  11. }
  12. try {
  13. logger.info('Starting database initialization...');
  14. // Create tables based on database type
  15. const dbType = process.env.DB_TYPE || 'postgres';
  16. switch (dbType) {
  17. case 'mysql':
  18. case 'postgres':
  19. await this.initializeRelationalDatabase();
  20. break;
  21. case 'sqlite':
  22. default:
  23. await this.initializeSQLite();
  24. break;
  25. }
  26. this.initialized = true;
  27. logger.info('Database initialization completed successfully');
  28. } catch (error) {
  29. logger.error('Database initialization failed:', error);
  30. throw error;
  31. }
  32. }
  33. async initializeRelationalDatabase() {
  34. try {
  35. const dbType = process.env.DB_TYPE || 'postgres';
  36. if (dbType === 'mysql') {
  37. await this.initializeMySQL();
  38. } else if (dbType === 'postgres') {
  39. await this.initializePostgreSQL();
  40. }
  41. } catch (error) {
  42. logger.error('Error creating relational database tables:', error);
  43. throw error;
  44. }
  45. }
  46. async initializeMySQL() {
  47. try {
  48. // Create candles_h1 table for storing H1 candlestick data
  49. const createCandlesH1TableQuery = `
  50. CREATE TABLE IF NOT EXISTS candles_h1 (
  51. id INT AUTO_INCREMENT PRIMARY KEY,
  52. symbol TEXT NOT NULL,
  53. market TEXT NOT NULL,
  54. open FLOAT NOT NULL,
  55. high FLOAT NOT NULL,
  56. low FLOAT NOT NULL,
  57. close FLOAT NOT NULL,
  58. volume FLOAT NOT NULL,
  59. timestamp TIMESTAMP NOT NULL,
  60. UNIQUE KEY unique_symbol_timestamp (symbol, timestamp),
  61. INDEX idx_symbol (symbol),
  62. INDEX idx_market (market),
  63. INDEX idx_timestamp (timestamp)
  64. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
  65. `;
  66. await executeNonQuery(createCandlesH1TableQuery);
  67. logger.info('MySQL candles_h1 table created successfully');
  68. // Create live_prices table for real-time price updates
  69. const createLivePricesTableQuery = `
  70. CREATE TABLE IF NOT EXISTS live_prices (
  71. id INT AUTO_INCREMENT PRIMARY KEY,
  72. symbol TEXT NOT NULL,
  73. market TEXT NOT NULL,
  74. price FLOAT NOT NULL,
  75. updated_at TIMESTAMP NOT NULL,
  76. UNIQUE KEY unique_symbol_market (symbol, market),
  77. INDEX idx_symbol (symbol),
  78. INDEX idx_market (market),
  79. INDEX idx_updated_at (updated_at)
  80. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
  81. `;
  82. await executeNonQuery(createLivePricesTableQuery);
  83. logger.info('MySQL live_prices table created successfully');
  84. } catch (error) {
  85. logger.error('Error creating MySQL tables:', error);
  86. throw error;
  87. }
  88. }
  89. async initializePostgreSQL() {
  90. try {
  91. // Create candles_h1 table for PostgreSQL
  92. const createCandlesH1TableQuery = `
  93. CREATE TABLE IF NOT EXISTS candles_h1 (
  94. id SERIAL PRIMARY KEY,
  95. symbol TEXT NOT NULL,
  96. market TEXT NOT NULL,
  97. open FLOAT NOT NULL,
  98. high FLOAT NOT NULL,
  99. low FLOAT NOT NULL,
  100. close FLOAT NOT NULL,
  101. volume FLOAT NOT NULL,
  102. timestamp TIMESTAMP NOT NULL,
  103. UNIQUE(symbol, timestamp)
  104. );
  105. `;
  106. await executeNonQuery(createCandlesH1TableQuery);
  107. logger.info('PostgreSQL candles_h1 table created successfully');
  108. // Create indexes for candles_h1
  109. const createCandlesH1Indexes = [
  110. 'CREATE INDEX IF NOT EXISTS idx_candles_symbol ON candles_h1(symbol);',
  111. 'CREATE INDEX IF NOT EXISTS idx_candles_market ON candles_h1(market);',
  112. 'CREATE INDEX IF NOT EXISTS idx_candles_timestamp ON candles_h1(timestamp);'
  113. ];
  114. for (const indexQuery of createCandlesH1Indexes) {
  115. await executeNonQuery(indexQuery);
  116. }
  117. logger.info('PostgreSQL candles_h1 indexes created successfully');
  118. // Create live_prices table for PostgreSQL
  119. const createLivePricesTableQuery = `
  120. CREATE TABLE IF NOT EXISTS live_prices (
  121. id SERIAL PRIMARY KEY,
  122. symbol TEXT NOT NULL,
  123. market TEXT NOT NULL,
  124. price FLOAT NOT NULL,
  125. updated_at TIMESTAMP NOT NULL,
  126. UNIQUE(symbol, market)
  127. );
  128. `;
  129. await executeNonQuery(createLivePricesTableQuery);
  130. logger.info('PostgreSQL live_prices table created successfully');
  131. // Create indexes for live_prices
  132. const createLivePricesIndexes = [
  133. 'CREATE INDEX IF NOT EXISTS idx_live_symbol ON live_prices(symbol);',
  134. 'CREATE INDEX IF NOT EXISTS idx_live_market ON live_prices(market);',
  135. 'CREATE INDEX IF NOT EXISTS idx_live_updated_at ON live_prices(updated_at);'
  136. ];
  137. for (const indexQuery of createLivePricesIndexes) {
  138. await executeNonQuery(indexQuery);
  139. }
  140. logger.info('PostgreSQL live_prices indexes created successfully');
  141. } catch (error) {
  142. logger.error('Error creating PostgreSQL tables:', error);
  143. throw error;
  144. }
  145. }
  146. async initializeSQLite() {
  147. try {
  148. // Create candles_h1 table for SQLite
  149. const createCandlesH1TableQuery = `
  150. CREATE TABLE IF NOT EXISTS candles_h1 (
  151. id INTEGER PRIMARY KEY AUTOINCREMENT,
  152. symbol TEXT NOT NULL,
  153. market TEXT NOT NULL,
  154. open REAL NOT NULL,
  155. high REAL NOT NULL,
  156. low REAL NOT NULL,
  157. close REAL NOT NULL,
  158. volume REAL NOT NULL,
  159. timestamp DATETIME NOT NULL,
  160. UNIQUE(symbol, timestamp)
  161. );
  162. `;
  163. await executeNonQuery(createCandlesH1TableQuery);
  164. logger.info('SQLite candles_h1 table created successfully');
  165. // Create indexes for candles_h1
  166. const createCandlesH1Indexes = [
  167. 'CREATE INDEX IF NOT EXISTS idx_candles_symbol ON candles_h1(symbol);',
  168. 'CREATE INDEX IF NOT EXISTS idx_candles_market ON candles_h1(market);',
  169. 'CREATE INDEX IF NOT EXISTS idx_candles_timestamp ON candles_h1(timestamp);'
  170. ];
  171. for (const indexQuery of createCandlesH1Indexes) {
  172. await executeNonQuery(indexQuery);
  173. }
  174. logger.info('SQLite candles_h1 indexes created successfully');
  175. // Create live_prices table for SQLite
  176. const createLivePricesTableQuery = `
  177. CREATE TABLE IF NOT EXISTS live_prices (
  178. id INTEGER PRIMARY KEY AUTOINCREMENT,
  179. symbol TEXT NOT NULL,
  180. market TEXT NOT NULL,
  181. price REAL NOT NULL,
  182. updated_at DATETIME NOT NULL,
  183. UNIQUE(symbol, market)
  184. );
  185. `;
  186. await executeNonQuery(createLivePricesTableQuery);
  187. logger.info('SQLite live_prices table created successfully');
  188. // Create indexes for live_prices
  189. const createLivePricesIndexes = [
  190. 'CREATE INDEX IF NOT EXISTS idx_live_symbol ON live_prices(symbol);',
  191. 'CREATE INDEX IF NOT EXISTS idx_live_market ON live_prices(market);',
  192. 'CREATE INDEX IF NOT EXISTS idx_live_updated_at ON live_prices(updated_at);'
  193. ];
  194. for (const indexQuery of createLivePricesIndexes) {
  195. await executeNonQuery(indexQuery);
  196. }
  197. logger.info('SQLite live_prices indexes created successfully');
  198. } catch (error) {
  199. logger.error('Error creating SQLite tables:', error);
  200. throw error;
  201. }
  202. }
  203. // Removed all sample data generation methods as per user requirements
  204. async reset() {
  205. try {
  206. logger.info('Resetting database...');
  207. const dbType = process.env.DB_TYPE || 'postgres';
  208. // Drop tables in correct order (considering foreign key constraints)
  209. if (dbType === 'sqlite') {
  210. await executeNonQuery('DROP TABLE IF EXISTS candles_h1');
  211. await executeNonQuery('DROP TABLE IF EXISTS live_prices');
  212. } else {
  213. await executeNonQuery('DROP TABLE IF EXISTS candles_h1');
  214. await executeNonQuery('DROP TABLE IF EXISTS live_prices');
  215. }
  216. this.initialized = false;
  217. logger.info('Database reset completed');
  218. // Reinitialize
  219. await this.initialize();
  220. } catch (error) {
  221. logger.error('Error resetting database:', error);
  222. throw error;
  223. }
  224. }
  225. async getStats() {
  226. try {
  227. const dbType = process.env.DB_TYPE || 'postgres';
  228. let candlesH1Count, livePricesCount;
  229. if (dbType === 'sqlite') {
  230. candlesH1Count = await executeQuery('SELECT COUNT(*) as count FROM candles_h1');
  231. livePricesCount = await executeQuery('SELECT COUNT(*) as count FROM live_prices');
  232. } else {
  233. candlesH1Count = await executeQuery('SELECT COUNT(*) as count FROM candles_h1');
  234. livePricesCount = await executeQuery('SELECT COUNT(*) as count FROM live_prices');
  235. }
  236. // Handle different database result formats
  237. let candlesH1 = 0;
  238. let livePrices = 0;
  239. if (candlesH1Count && candlesH1Count.length > 0) {
  240. candlesH1 = candlesH1Count[0].count || 0;
  241. }
  242. if (livePricesCount && livePricesCount.length > 0) {
  243. livePrices = livePricesCount[0].count || 0;
  244. }
  245. return {
  246. candles_h1: candlesH1,
  247. live_prices: livePrices,
  248. initialized: this.initialized
  249. };
  250. } catch (error) {
  251. logger.error('Error getting database stats:', error);
  252. return {
  253. candles_h1: 0,
  254. live_prices: 0,
  255. initialized: false
  256. };
  257. }
  258. }
  259. }
  260. const databaseInitializer = new DatabaseInitializer();
  261. // Export functions for external use
  262. const initializeDatabase = () => databaseInitializer.initialize();
  263. const resetDatabase = () => databaseInitializer.reset();
  264. const getDatabaseStats = () => databaseInitializer.getStats();
  265. module.exports = {
  266. DatabaseInitializer,
  267. initializeDatabase,
  268. resetDatabase,
  269. getDatabaseStats,
  270. databaseInitializer
  271. };