RdbUtils.ets 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. import relationalStore from '@ohos.data.relationalStore';
  2. import { LogUtil, StrUtil } from '@pura/harmony-utils';
  3. import Logger from './Logger';
  4. import NetAxiosUtil from './NetAxiosUtil';
  5. //
  6. interface GeneratedObjectLiteralInterface_1 {
  7. tableName: string;
  8. sqlCreate: string;
  9. columns: string[];
  10. }
  11. export default class RdbUtils {
  12. private rdbStore: relationalStore.RdbStore | null = null;
  13. private tableName: string;
  14. private sqlCreateTable: string;
  15. private columns: Array<string>;
  16. static readonly RDB_TAG: string = 'heanup onecold RdbUtils';
  17. /**
  18. * Rdb数据库配置。
  19. * name:数据库名称
  20. * securityLevel:数据库安全级别
  21. */
  22. static readonly STORE_CONFIG: relationalStore.StoreConfig = {
  23. name: 'mediaDB.db',
  24. securityLevel: relationalStore.SecurityLevel.S1
  25. };
  26. /**
  27. * 表配置信息
  28. * tableName:表名称
  29. * sqlCreate:创建表的语句
  30. * columns:表的列项目
  31. */
  32. static readonly MEDIA_TABLE: GeneratedObjectLiteralInterface_1 = {
  33. tableName: 'mediaTable',
  34. sqlCreate: ' CREATE TABLE IF NOT EXISTS mediaTable (\n' +
  35. ' id TEXT NOT NULL,\n' +
  36. ' name TEXT NOT NULL,\n' +
  37. ' filePath TEXT NOT NULL UNIQUE,\n' +
  38. ' mtype INTEGER NOT NULL,\n' +
  39. ' videoSize INTEGER,\n' +
  40. ' cTime TEXT NOT NULL,\n' +
  41. ' size TEXT,\n' +
  42. ' artist TEXT,\n' +
  43. ' album TEXT,\n' +
  44. ' fileName TEXT ,\n' +
  45. ' parentPath TEXT,\n' +
  46. ' isFav INTEGER,\n' +
  47. ' pixelMapPath TEXT,\n' +
  48. ' pixelMapToString TEXT,\n' +
  49. ' duration TEXT,\n' +
  50. ' sampleRate TEXT,\n' +
  51. ' playCount INTEGER DEFAULT 0,\n' +
  52. ' lastPlayedStr TEXT,\n' +
  53. ' trackCount TEXT,\n' +
  54. ' lyricContent TEXT,\n' +
  55. ' md5Str TEXT,\n' +
  56. ' extra_json TEXT,\n' +
  57. ' pyStr TEXT,\n' +
  58. ' bit_rate TEXT,\n' +
  59. ' probe_score INTEGER DEFAULT 0,\n' +
  60. ' year TEXT,\n' +
  61. ' nb_streams INTEGER DEFAULT 0,\n' +
  62. ' nb_programs INTEGER DEFAULT 0,\n' +
  63. ' genre TEXT,\n' +
  64. ' track TEXT,\n' +
  65. ' bits_per_raw_sample TEXT,\n' +
  66. ' channels TEXT,\n' +
  67. ' channel_layout TEXT,\n' +
  68. ' start_time TEXT,\n' +
  69. ' ALBUMARTIST TEXT,\n' +
  70. ' COMPOSER TEXT,\n' +
  71. ' LYRICIST TEXT,\n' +
  72. ' COMMENT TEXT,\n' +
  73. ' disc TEXT,\n' +
  74. ' mimeType TEXT' +
  75. ')',
  76. columns: ['id', 'name', 'filePath','mtype', 'videoSize', 'cTime','size', 'artist', 'album',
  77. 'fileName','parentPath','isFav','pixelMapPath','pixelMapToString',
  78. 'duration', 'sampleRate','playCount', 'lastPlayedStr', 'trackCount',
  79. 'lyricContent','md5Str','extra_json','pyStr','bit_rate','probe_score','year','nb_streams','nb_programs',
  80. 'genre','track', 'bits_per_raw_sample','channels', 'channel_layout','start_time',
  81. 'ALBUMARTIST', 'COMPOSER','LYRICIST','COMMENT','COMMENT','disc',
  82. 'mimeType']
  83. };
  84. /**
  85. * 歌单表配置
  86. */
  87. static readonly PLAYLIST_TABLE: GeneratedObjectLiteralInterface_1 = {
  88. tableName: 'playlistTable',
  89. sqlCreate: 'CREATE TABLE IF NOT EXISTS playlistTable (\n' +
  90. 'id TEXT PRIMARY KEY NOT NULL,\n' +
  91. 'name TEXT NOT NULL,\n' +
  92. 'coverPath TEXT,\n' +
  93. 'description TEXT,\n' +
  94. 'createTime TEXT NOT NULL,\n' +
  95. 'updateTime TEXT NOT NULL,\n' +
  96. 'songCount INTEGER DEFAULT 0,\n' +
  97. 'sortOrder INTEGER DEFAULT 0\n' +
  98. ')',
  99. columns: ['id', 'name', 'coverPath', 'description', 'createTime', 'updateTime', 'songCount', 'sortOrder']
  100. };
  101. /**
  102. * 歌单歌曲关联表配置
  103. */
  104. static readonly PLAYLIST_SONG_TABLE: GeneratedObjectLiteralInterface_1 = {
  105. tableName: 'playlistSongTable',
  106. sqlCreate: 'CREATE TABLE IF NOT EXISTS playlistSongTable (\n' +
  107. 'id TEXT PRIMARY KEY NOT NULL,\n' +
  108. 'playlistId TEXT NOT NULL,\n' +
  109. 'songFilePath TEXT NOT NULL,\n' +
  110. 'addTime TEXT NOT NULL,\n' +
  111. 'sortOrder INTEGER DEFAULT 0,\n' +
  112. 'UNIQUE(playlistId, songFilePath)\n' +
  113. ')',
  114. columns: ['id', 'playlistId', 'songFilePath', 'addTime', 'sortOrder']
  115. };
  116. constructor(tableName: string, sqlCreateTable: string, columns: Array<string>) {
  117. this.tableName = tableName;
  118. this.sqlCreateTable = sqlCreateTable;
  119. this.columns = columns;
  120. }
  121. getRdbStore(context:Context,callback: Function = () => {
  122. }) {
  123. if (!callback || typeof callback === 'undefined' || callback === undefined) {
  124. Logger.info(RdbUtils.RDB_TAG, 'getRdbStore() has no callback!');
  125. return;
  126. }
  127. if (this.rdbStore !== null) {
  128. Logger.info(RdbUtils.RDB_TAG, 'The rdbStore exists.');
  129. callback();
  130. return
  131. }
  132. relationalStore.getRdbStore(context, RdbUtils.STORE_CONFIG, (err, rdb) => {
  133. if (err) {
  134. Logger.error(RdbUtils.RDB_TAG, `gerRdbStore() failed, err: ${err}`);
  135. return;
  136. }
  137. this.rdbStore = rdb;
  138. // 先创建表(如果不存在)
  139. this.rdbStore.executeSql(this.sqlCreateTable);
  140. // 检查数据库版本并更新列
  141. try {
  142. // 检查表结构
  143. this.checkAndUpdateTableColumns();
  144. // Logger.info(RdbUtils.RDB_TAG, `数据库表结构检查完成`);
  145. } catch (e) {
  146. Logger.error(RdbUtils.RDB_TAG, `检查表结构时出错: ${e.message}`);
  147. }
  148. callback();
  149. });
  150. }
  151. /**
  152. * 检查并更新表列结构
  153. * 使用表信息查询和ALTER TABLE添加缺失的列
  154. */
  155. private checkAndUpdateTableColumns() {
  156. if (!this.rdbStore) {
  157. Logger.error(RdbUtils.RDB_TAG, `数据库连接未初始化`);
  158. return;
  159. }
  160. try {
  161. // 查询表信息获取现有列
  162. const tableInfoQuery = `PRAGMA table_info(${this.tableName})`;
  163. // 使用Promise模式代替回调
  164. this.rdbStore.executeSql(tableInfoQuery)
  165. .then(() => {
  166. // 定义应该存在的列及其类型
  167. const requiredColumns: Record<string, string> = {
  168. 'duration': 'TEXT',
  169. 'sampleRate': 'TEXT',
  170. 'playCount': 'INTEGER DEFAULT 0',
  171. 'lastPlayedStr': 'TEXT',
  172. 'trackCount': 'TEXT',
  173. 'lyricContent': 'TEXT',
  174. 'md5Str': 'TEXT',
  175. 'extra_json': 'TEXT',
  176. 'mimeType': 'TEXT',
  177. 'pyStr': 'TEXT',
  178. 'bit_rate': 'TEXT',
  179. 'probe_score': 'INTEGER DEFAULT 0',
  180. 'year': 'TEXT',
  181. 'nb_streams': 'INTEGER DEFAULT 0',
  182. 'nb_programs': 'INTEGER DEFAULT 0',
  183. 'genre': 'TEXT',
  184. 'track': 'TEXT',
  185. 'bits_per_raw_sample': 'TEXT',
  186. 'channels': 'TEXT',
  187. 'channel_layout': 'TEXT',
  188. 'start_time': 'TEXT',
  189. 'ALBUMARTIST': 'TEXT',
  190. 'COMPOSER': 'TEXT',
  191. 'LYRICIST': 'TEXT',
  192. 'COMMENT': 'TEXT',
  193. 'disc': 'TEXT',
  194. };
  195. // 逐个添加列,不依赖于检查结果
  196. if (this.rdbStore) {
  197. // 遍历映射
  198. const columnEntries = Object.keys(requiredColumns);
  199. for (let i = 0; i < columnEntries.length; i++) {
  200. const column = columnEntries[i];
  201. const type = requiredColumns[column];
  202. const alterSql = `ALTER TABLE ${this.tableName} ADD COLUMN ${column} ${type}`;
  203. try {
  204. // 对每个列使用Promise模式
  205. this.rdbStore.executeSql(alterSql)
  206. .then(() => {
  207. Logger.info(RdbUtils.RDB_TAG, `成功添加列: ${column}`);
  208. })
  209. .catch((alterErr: Error) => {
  210. // 列可能已经存在,这是预期的错误
  211. // Logger.info(RdbUtils.RDB_TAG, `列 ${column} 可能已存在: ${alterErr.message}`);
  212. });
  213. } catch (e) {
  214. Logger.error(RdbUtils.RDB_TAG, `添加列 ${column} 出错: ${e.message}`);
  215. }
  216. }
  217. // 设置数据库版本
  218. if (this.rdbStore) {
  219. this.rdbStore.version = 1;
  220. // Logger.info(RdbUtils.RDB_TAG, `数据库升级完成,版本设置为 1`);
  221. }
  222. }
  223. })
  224. .catch((err: Error) => {
  225. Logger.error(RdbUtils.RDB_TAG, `获取表信息失败: ${err.message}`);
  226. });
  227. } catch (e) {
  228. Logger.error(RdbUtils.RDB_TAG, `检查表结构时出错: ${e.message}`);
  229. }
  230. }
  231. //检查是否存在相同id的记录,存在则不插入,进一步判断pixelMapPath字段,如果旧值为空而新值不为空,则更新该字段。
  232. async insertData(data: relationalStore.ValuesBucket, callback: Function = () => {},cover_api?:string) {
  233. if (!callback || typeof callback !== 'function') {
  234. Logger.info(RdbUtils.RDB_TAG, 'insertData() has no valid callback!');
  235. return;
  236. }
  237. const valueBucket: relationalStore.ValuesBucket = data;
  238. const id = valueBucket.id;
  239. let titleNameV = valueBucket.name;
  240. let artistV = valueBucket.artist ;
  241. let pixelMapPathV = valueBucket.pixelMapPath
  242. if (this.rdbStore) {
  243. // Create a predicate to check if the record exists
  244. const predicates = new relationalStore.RdbPredicates(this.tableName);
  245. predicates.equalTo('id', id);
  246. // Query the database
  247. this.rdbStore.query(predicates, async (err, resultSet) => {
  248. if (err) {
  249. Logger.error(RdbUtils.RDB_TAG, `Query failed, err: ${err}`);
  250. callback(false);
  251. return;
  252. }
  253. if (resultSet.rowCount > 0) {
  254. Logger.info(RdbUtils.RDB_TAG, `Record with id ${id} already exists. Skipping insert.`);
  255. //检查是否存在相同id的记录,存在则不插入,进一步判断pixelMapPath字段,如果旧值为空而新值不为空,则更新该字段。
  256. //20250924不判断pixelMapPath字段了,如果存在不插入,则返回
  257. if (resultSet.goToFirstRow()) {
  258. resultSet.close();
  259. return;
  260. // const existingPixelMapPath = resultSet.getString(resultSet.getColumnIndex('pixelMapPath'));
  261. // const name = resultSet.getString(resultSet.getColumnIndex('name'));
  262. // const artist = resultSet.getString(resultSet.getColumnIndex('artist'));
  263. // if ((!existingPixelMapPath || existingPixelMapPath.trim() === '')&& cover_api!==undefined) {
  264. // let newPixelMapPath = await NetAxiosUtil.getLyricCover(name,artist,cover_api)
  265. // console.info('onecold getLyricCover success. name= '+name);
  266. // console.info('onecold getLyricCover success. newPixelMapPath= '+newPixelMapPath);
  267. // if(StrUtil.isNotEmpty(newPixelMapPath)){
  268. // // Update pixelMapPath
  269. // const updateValues: relationalStore.ValuesBucket = { pixelMapPath: newPixelMapPath };
  270. // this.updateData(predicates, updateValues, (updateSuccess: boolean) => {
  271. // if (updateSuccess) {
  272. // Logger.info(RdbUtils.RDB_TAG, `onecold Updated pixelMapPath for id ${id}.`);
  273. // } else {
  274. // Logger.error(RdbUtils.RDB_TAG, `onecold Failed to update pixelMapPath for id ${id}.`);
  275. // }
  276. // callback(updateSuccess);
  277. // });
  278. // }
  279. //
  280. // resultSet.close();
  281. // return;
  282. // }
  283. }
  284. Logger.info(RdbUtils.RDB_TAG, `No update needed for id ${id}.`);
  285. callback(false);
  286. return;
  287. }
  288. if (!this.rdbStore) {
  289. Logger.error(RdbUtils.RDB_TAG, 'RdbStore is not initialized.');
  290. callback(false);
  291. return;
  292. }
  293. //不存在相同记录 ,判断要不要去请求getLyricCover
  294. if(pixelMapPathV==undefined||pixelMapPathV.toString()==='' ){
  295. valueBucket.pixelMapPath = await NetAxiosUtil.getLyricCover(titleNameV+'',artistV+'',cover_api)
  296. }
  297. console.info('onecold getLyricCover pixelMapPathV1= '+pixelMapPathV);
  298. // Proceed with insert if record does not exist
  299. this.rdbStore.insert(this.tableName, valueBucket, (err, ret) => {
  300. if (err) {
  301. Logger.error(RdbUtils.RDB_TAG, `insertData() failed, err: ${err}`);
  302. callback(false);
  303. return;
  304. }
  305. Logger.info(RdbUtils.RDB_TAG, `insertData() finished: ${ret}`);
  306. callback(ret);
  307. });
  308. });
  309. }else{
  310. Logger.error(RdbUtils.RDB_TAG, 'RdbStore2 is not initialized.');
  311. }
  312. }
  313. deleteData(predicates: relationalStore.RdbPredicates, callback: Function = () => {
  314. }) {
  315. if (!callback || typeof callback === 'undefined' || callback === undefined) {
  316. Logger.info(RdbUtils.RDB_TAG, 'deleteData() has no callback!');
  317. return;
  318. }
  319. let resFlag: boolean = false;
  320. if (this.rdbStore) {
  321. this.rdbStore.delete(predicates, (err, ret) => {
  322. if (err) {
  323. Logger.info('xiaozheng 校正数据开始 deleteData5 = ' )
  324. Logger.error(RdbUtils.RDB_TAG, `deleteData() failed, err: ${err}`);
  325. callback(resFlag);
  326. return;
  327. }
  328. Logger.info('xiaozheng 校正数据开始 deleteData6 = ' )
  329. Logger.info(RdbUtils.RDB_TAG, `deleteData() finished: ${ret}`);
  330. callback(!resFlag);
  331. });
  332. }else{
  333. Logger.info(RdbUtils.RDB_TAG, 'deleteData rdbStore() 未初始化!');
  334. }
  335. }
  336. updateData(predicates: relationalStore.RdbPredicates, data: relationalStore.ValuesBucket, callback: Function = () => {
  337. }) {
  338. if (!callback || typeof callback === 'undefined' || callback === undefined) {
  339. Logger.info(RdbUtils.RDB_TAG, 'updateDate() has no callback!');
  340. return;
  341. }
  342. let resFlag: boolean = false;
  343. const valueBucket: relationalStore.ValuesBucket = data;
  344. if (this.rdbStore) {
  345. this.rdbStore.update(valueBucket, predicates, (err, ret) => {
  346. if (err) {
  347. Logger.error(RdbUtils.RDB_TAG, `updateData() failed, err: ${err}`);
  348. callback(resFlag);
  349. return;
  350. }
  351. Logger.info(RdbUtils.RDB_TAG, `updateData() finished: ${ret}`);
  352. callback(!resFlag);
  353. });
  354. }
  355. }
  356. query(predicates: relationalStore.RdbPredicates, callback: Function = () => {
  357. }) {
  358. if (!callback || typeof callback === 'undefined' || callback === undefined) {
  359. Logger.info(RdbUtils.RDB_TAG, 'query() has no callback!');
  360. return;
  361. }
  362. if (this.rdbStore) {
  363. this.rdbStore.query(predicates, this.columns, (err, resultSet) => {
  364. if (err) {
  365. Logger.error(RdbUtils.RDB_TAG, `query() failed, err: ${err}`);
  366. return;
  367. }
  368. // Logger.info(RdbUtils.RDB_TAG, 'query() finished.');
  369. callback(resultSet);
  370. resultSet.close();
  371. });
  372. }
  373. }
  374. }