RdbUtils.ets 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  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 = '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. constructor(tableName: string, sqlCreateTable: string, columns: Array<string>) {
  85. this.tableName = tableName;
  86. this.sqlCreateTable = sqlCreateTable;
  87. this.columns = columns;
  88. }
  89. getRdbStore(context:Context,callback: Function = () => {
  90. }) {
  91. if (!callback || typeof callback === 'undefined' || callback === undefined) {
  92. Logger.info(RdbUtils.RDB_TAG, 'getRdbStore() has no callback!');
  93. return;
  94. }
  95. if (this.rdbStore !== null) {
  96. Logger.info(RdbUtils.RDB_TAG, 'The rdbStore exists.');
  97. callback();
  98. return
  99. }
  100. relationalStore.getRdbStore(context, RdbUtils.STORE_CONFIG, (err, rdb) => {
  101. if (err) {
  102. Logger.error(RdbUtils.RDB_TAG, `gerRdbStore() failed, err: ${err}`);
  103. return;
  104. }
  105. this.rdbStore = rdb;
  106. // 先创建表(如果不存在)
  107. this.rdbStore.executeSql(this.sqlCreateTable);
  108. // 检查数据库版本并更新列
  109. try {
  110. // 检查表结构
  111. this.checkAndUpdateTableColumns();
  112. // Logger.info(RdbUtils.RDB_TAG, `数据库表结构检查完成`);
  113. } catch (e) {
  114. Logger.error(RdbUtils.RDB_TAG, `检查表结构时出错: ${e.message}`);
  115. }
  116. callback();
  117. });
  118. }
  119. /**
  120. * 检查并更新表列结构
  121. * 使用表信息查询和ALTER TABLE添加缺失的列
  122. */
  123. private checkAndUpdateTableColumns() {
  124. if (!this.rdbStore) {
  125. Logger.error(RdbUtils.RDB_TAG, `数据库连接未初始化`);
  126. return;
  127. }
  128. try {
  129. // 查询表信息获取现有列
  130. const tableInfoQuery = `PRAGMA table_info(${this.tableName})`;
  131. // 使用Promise模式代替回调
  132. this.rdbStore.executeSql(tableInfoQuery)
  133. .then(() => {
  134. // 定义应该存在的列及其类型
  135. const requiredColumns: Record<string, string> = {
  136. 'duration': 'TEXT',
  137. 'sampleRate': 'TEXT',
  138. 'playCount': 'INTEGER DEFAULT 0',
  139. 'lastPlayedStr': 'TEXT',
  140. 'trackCount': 'TEXT',
  141. 'lyricContent': 'TEXT',
  142. 'md5Str': 'TEXT',
  143. 'extra_json': 'TEXT',
  144. 'mimeType': 'TEXT',
  145. 'pyStr': 'TEXT',
  146. 'bit_rate': 'TEXT',
  147. 'probe_score': 'INTEGER DEFAULT 0',
  148. 'year': 'TEXT',
  149. 'nb_streams': 'INTEGER DEFAULT 0',
  150. 'nb_programs': 'INTEGER DEFAULT 0',
  151. 'genre': 'TEXT',
  152. 'track': 'TEXT',
  153. 'bits_per_raw_sample': 'TEXT',
  154. 'channels': 'TEXT',
  155. 'channel_layout': 'TEXT',
  156. 'start_time': 'TEXT',
  157. 'ALBUMARTIST': 'TEXT',
  158. 'COMPOSER': 'TEXT',
  159. 'LYRICIST': 'TEXT',
  160. 'COMMENT': 'TEXT',
  161. 'disc': 'TEXT',
  162. };
  163. // 逐个添加列,不依赖于检查结果
  164. if (this.rdbStore) {
  165. // 遍历映射
  166. const columnEntries = Object.keys(requiredColumns);
  167. for (let i = 0; i < columnEntries.length; i++) {
  168. const column = columnEntries[i];
  169. const type = requiredColumns[column];
  170. const alterSql = `ALTER TABLE ${this.tableName} ADD COLUMN ${column} ${type}`;
  171. try {
  172. // 对每个列使用Promise模式
  173. this.rdbStore.executeSql(alterSql)
  174. .then(() => {
  175. Logger.info(RdbUtils.RDB_TAG, `成功添加列: ${column}`);
  176. })
  177. .catch((alterErr: Error) => {
  178. // 列可能已经存在,这是预期的错误
  179. // Logger.info(RdbUtils.RDB_TAG, `列 ${column} 可能已存在: ${alterErr.message}`);
  180. });
  181. } catch (e) {
  182. Logger.error(RdbUtils.RDB_TAG, `添加列 ${column} 出错: ${e.message}`);
  183. }
  184. }
  185. // 设置数据库版本
  186. if (this.rdbStore) {
  187. this.rdbStore.version = 1;
  188. // Logger.info(RdbUtils.RDB_TAG, `数据库升级完成,版本设置为 1`);
  189. }
  190. }
  191. })
  192. .catch((err: Error) => {
  193. Logger.error(RdbUtils.RDB_TAG, `获取表信息失败: ${err.message}`);
  194. });
  195. } catch (e) {
  196. Logger.error(RdbUtils.RDB_TAG, `检查表结构时出错: ${e.message}`);
  197. }
  198. }
  199. //检查是否存在相同id的记录,存在则不插入,进一步判断pixelMapPath字段,如果旧值为空而新值不为空,则更新该字段。
  200. async insertData(data: relationalStore.ValuesBucket, callback: Function = () => {},cover_api?:string) {
  201. if (!callback || typeof callback !== 'function') {
  202. Logger.info(RdbUtils.RDB_TAG, 'insertData() has no valid callback!');
  203. return;
  204. }
  205. const valueBucket: relationalStore.ValuesBucket = data;
  206. const id = valueBucket.id;
  207. let titleNameV = valueBucket.name;
  208. let artistV = valueBucket.artist ;
  209. let pixelMapPathV = valueBucket.pixelMapPath
  210. if (this.rdbStore) {
  211. // Create a predicate to check if the record exists
  212. const predicates = new relationalStore.RdbPredicates(this.tableName);
  213. predicates.equalTo('id', id);
  214. // Query the database
  215. this.rdbStore.query(predicates, async (err, resultSet) => {
  216. if (err) {
  217. Logger.error(RdbUtils.RDB_TAG, `Query failed, err: ${err}`);
  218. callback(false);
  219. return;
  220. }
  221. if (resultSet.rowCount > 0) {
  222. Logger.info(RdbUtils.RDB_TAG, `Record with id ${id} already exists. Skipping insert.`);
  223. //检查是否存在相同id的记录,存在则不插入,进一步判断pixelMapPath字段,如果旧值为空而新值不为空,则更新该字段。
  224. if (resultSet.goToFirstRow()) {
  225. const existingPixelMapPath = resultSet.getString(resultSet.getColumnIndex('pixelMapPath'));
  226. const name = resultSet.getString(resultSet.getColumnIndex('name'));
  227. const artist = resultSet.getString(resultSet.getColumnIndex('artist'));
  228. if ((!existingPixelMapPath || existingPixelMapPath.trim() === '')&& cover_api!==undefined) {
  229. let newPixelMapPath = await NetAxiosUtil.getLyricCover(name,artist,cover_api)
  230. console.info('onecold getLyricCover success. name= '+name);
  231. console.info('onecold getLyricCover success. newPixelMapPath= '+newPixelMapPath);
  232. if(StrUtil.isNotEmpty(newPixelMapPath)){
  233. // Update pixelMapPath
  234. const updateValues: relationalStore.ValuesBucket = { pixelMapPath: newPixelMapPath };
  235. this.updateData(predicates, updateValues, (updateSuccess: boolean) => {
  236. if (updateSuccess) {
  237. Logger.info(RdbUtils.RDB_TAG, `onecold Updated pixelMapPath for id ${id}.`);
  238. } else {
  239. Logger.error(RdbUtils.RDB_TAG, `onecold Failed to update pixelMapPath for id ${id}.`);
  240. }
  241. callback(updateSuccess);
  242. });
  243. }
  244. resultSet.close();
  245. return;
  246. }
  247. }
  248. Logger.info(RdbUtils.RDB_TAG, `No update needed for id ${id}.`);
  249. callback(false);
  250. return;
  251. }
  252. if (!this.rdbStore) {
  253. Logger.error(RdbUtils.RDB_TAG, 'RdbStore is not initialized.');
  254. callback(false);
  255. return;
  256. }
  257. //不存在相同记录 ,判断要不要去请求getLyricCover
  258. if(pixelMapPathV==undefined||pixelMapPathV.toString()==='' ){
  259. valueBucket.pixelMapPath = await NetAxiosUtil.getLyricCover(titleNameV+'',artistV+'',cover_api)
  260. }
  261. console.info('onecold getLyricCover pixelMapPathV1= '+pixelMapPathV);
  262. // Proceed with insert if record does not exist
  263. this.rdbStore.insert(this.tableName, valueBucket, (err, ret) => {
  264. if (err) {
  265. Logger.error(RdbUtils.RDB_TAG, `insertData() failed, err: ${err}`);
  266. callback(false);
  267. return;
  268. }
  269. Logger.info(RdbUtils.RDB_TAG, `insertData() finished: ${ret}`);
  270. callback(ret);
  271. });
  272. });
  273. }else{
  274. Logger.error(RdbUtils.RDB_TAG, 'RdbStore2 is not initialized.');
  275. }
  276. }
  277. deleteData(predicates: relationalStore.RdbPredicates, callback: Function = () => {
  278. }) {
  279. if (!callback || typeof callback === 'undefined' || callback === undefined) {
  280. Logger.info(RdbUtils.RDB_TAG, 'deleteData() has no callback!');
  281. return;
  282. }
  283. let resFlag: boolean = false;
  284. if (this.rdbStore) {
  285. this.rdbStore.delete(predicates, (err, ret) => {
  286. if (err) {
  287. Logger.info('xiaozheng 校正数据开始 deleteData5 = ' )
  288. Logger.error(RdbUtils.RDB_TAG, `deleteData() failed, err: ${err}`);
  289. callback(resFlag);
  290. return;
  291. }
  292. Logger.info('xiaozheng 校正数据开始 deleteData6 = ' )
  293. Logger.info(RdbUtils.RDB_TAG, `deleteData() finished: ${ret}`);
  294. callback(!resFlag);
  295. });
  296. }else{
  297. Logger.info(RdbUtils.RDB_TAG, 'deleteData rdbStore() 未初始化!');
  298. }
  299. }
  300. updateData(predicates: relationalStore.RdbPredicates, data: relationalStore.ValuesBucket, callback: Function = () => {
  301. }) {
  302. if (!callback || typeof callback === 'undefined' || callback === undefined) {
  303. Logger.info(RdbUtils.RDB_TAG, 'updateDate() has no callback!');
  304. return;
  305. }
  306. let resFlag: boolean = false;
  307. const valueBucket: relationalStore.ValuesBucket = data;
  308. if (this.rdbStore) {
  309. this.rdbStore.update(valueBucket, predicates, (err, ret) => {
  310. if (err) {
  311. Logger.error(RdbUtils.RDB_TAG, `updateData() failed, err: ${err}`);
  312. callback(resFlag);
  313. return;
  314. }
  315. Logger.info(RdbUtils.RDB_TAG, `updateData() finished: ${ret}`);
  316. callback(!resFlag);
  317. });
  318. }
  319. }
  320. query(predicates: relationalStore.RdbPredicates, callback: Function = () => {
  321. }) {
  322. if (!callback || typeof callback === 'undefined' || callback === undefined) {
  323. Logger.info(RdbUtils.RDB_TAG, 'query() has no callback!');
  324. return;
  325. }
  326. if (this.rdbStore) {
  327. this.rdbStore.query(predicates, this.columns, (err, resultSet) => {
  328. if (err) {
  329. Logger.error(RdbUtils.RDB_TAG, `query() failed, err: ${err}`);
  330. return;
  331. }
  332. // Logger.info(RdbUtils.RDB_TAG, 'query() finished.');
  333. callback(resultSet);
  334. resultSet.close();
  335. });
  336. }
  337. }
  338. }