/*
* Copyright (c) Huawei Technologies Co., Ltd. 2024-2025. All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type common from '@ohos.app.ability.common';
import relationalStore from '@ohos.data.relationalStore';
import i18n from '@ohos.i18n';
import { LogUtil } from '../utils/LogUtil';
import DatabaseManager from './DatabaseManager';
import {
ItemInfo,
ITEMINFO_TABLE,
SQL_CREATE_ITEMINFO_TABLE,
SQL_UPDATE_ITEM_INFO,
ENABLED_TRUE,
ENABLED_FALSE,
SQL_DELETE_ITEM_INFO_TABLE,
} from './types';
import { HiSysEventUtil } from '../systemEvent/HiSysEventUtil';
import { CheckEmptyUtils } from '../utils/CheckEmptyUtils';
import { RdbTaskPool } from '../rdb/RdbTaskPool';
import { HiSysRdbEventGroup } from '../systemEvent/BehaviorEventConsts';
const TAG: string = 'SearchItemInfoManager';
const RDB_CORRUPTION_ERROR_CODE: number = 14800011;
export class SearchItemInfoManager extends DatabaseManager {
/**
* 获取关系数据库存储对象
* 如果已初始化过,则直接返回之前获取的对象
* 如果没有初始化过,则使用接口获取对象,并执行数据库建表命令,如果表未创建,则会创建一张新的表
*
* @return 关系数据库存储对象
*/
async getRdbStore(): Promise<relationalStore.RdbStore> {
const rdbStore = await super.getRdbStore(SQL_CREATE_ITEMINFO_TABLE);
return rdbStore;
}
async batchInsertSearchItemData(itemInfoList: Array<ItemInfo>, hideSearchItems: Array<string>,
context?: common.Context): Promise<void> {
try {
LogUtil.info(`${TAG} start batchInsertSearchItemData`);
let searchItemInfos: relationalStore.ValuesBucket[] = [];
itemInfoList.forEach((itemInfo) => {
if (hideSearchItems && !hideSearchItems.includes(itemInfo.itemName)) {
LogUtil.info(`${TAG} insert search item name:${itemInfo.itemName} enable: ${itemInfo.enable}`);
searchItemInfos.push(this.getDbBucketList(itemInfo));
}
})
LogUtil.info(`${TAG} batchInsertSearchItemData beginTransaction searchItemInfos size:${searchItemInfos.length}`);
let result = await RdbTaskPool.getInstance().batchInsert(ITEMINFO_TABLE, searchItemInfos, context);
LogUtil.info(`${TAG} batchInsertSearchItemData result: ${result}`);
HiSysEventUtil.searchReportEvent(TAG, 'batchInsertSearchItemData success');
} catch (error) {
LogUtil.error(`${TAG} batchInsertSearchItemData error: ${error?.message}`);
HiSysEventUtil.searchReportEvent(TAG, `batchInsertSearchItemData error: ${JSON.stringify(error)}`);
}
}
private getDbBucketList(itemInfo: ItemInfo): relationalStore.ValuesBucket {
return {
'locale': itemInfo.locale,
'itemName': itemInfo.itemName,
'itemTitle': itemInfo.itemTitle,
'itemDescription': itemInfo.itemDescription,
'entryKey': itemInfo.entryKey,
'pageTitle': itemInfo.pageTitle,
'params': itemInfo.params,
'enable': itemInfo.enable ? ENABLED_TRUE : ENABLED_FALSE,
'icon': itemInfo.icon,
'alias': itemInfo.alias,
'childItems': itemInfo.childItems,
'path': itemInfo.path,
'bundleName': itemInfo.bundleName,
'checkType': itemInfo.checkType,
'checkKey': itemInfo.checkKey,
'checkValue': itemInfo.checkValue
}
}
async removeSearchItem(entryKey: string[]): Promise<void> {
const rdbStore = await this.getRdbStore();
try {
rdbStore.beginTransaction();
const predicates = new relationalStore.RdbPredicates(ITEMINFO_TABLE);
predicates.in('entryKey', entryKey);
await rdbStore.delete(predicates);
rdbStore.commit();
LogUtil.info(`${TAG} removeSearchItem successfully.`);
HiSysEventUtil.searchReportEvent(TAG, 'removeSearchItem success');
} catch (error) {
LogUtil.error(`${TAG} removeSearchItem failed, message: ${error?.message}, code: ${error.code}`);
HiSysEventUtil.searchReportEvent(TAG, `removeSearchItem error: ${JSON.stringify(error)}`);
if (error.code === RDB_CORRUPTION_ERROR_CODE) {
HiSysEventUtil.reportDefaultFaultEvent(HiSysRdbEventGroup.EVENT_NAME,
HiSysRdbEventGroup.SETTINGS_DATA_RDB_CORRUPTION);
await super.restoreRdb();
}
rdbStore.rollBack();
}
}
async removeSearchItemByEntryKey(entryKey: string): Promise<void> {
const rdbStore = await this.getRdbStore();
try {
rdbStore.beginTransaction();
const predicates = new relationalStore.RdbPredicates(ITEMINFO_TABLE);
predicates.equalTo('entryKey', entryKey);
await rdbStore.delete(predicates);
rdbStore.commit();
LogUtil.info(`${TAG} removeSearchItemByEntryKey successfully.`);
HiSysEventUtil.searchReportEvent(TAG, 'removeSearchItemByEntryKey success');
} catch (error) {
LogUtil.error(`${TAG} removeSearchItemByEntryKey failed, message: ${error?.message}, code: ${error?.code}`);
HiSysEventUtil.searchReportEvent(TAG, `removeSearchItemByEntryKey error: ${JSON.stringify(error)}`);
if (error.code === RDB_CORRUPTION_ERROR_CODE) {
HiSysEventUtil.reportDefaultFaultEvent(HiSysRdbEventGroup.EVENT_NAME,
HiSysRdbEventGroup.SETTINGS_DATA_RDB_CORRUPTION);
await super.restoreRdb();
}
rdbStore.rollBack();
}
}
async updateSearchItemData(): Promise<void> {
const rdbStore = await this.getRdbStore();
try {
LogUtil.info(`${TAG} start updateSearchItemData`);
rdbStore.beginTransaction();
await rdbStore.executeSql(SQL_UPDATE_ITEM_INFO);
rdbStore.commit();
LogUtil.info(`${TAG} updateSearchItemData success`);
HiSysEventUtil.searchReportEvent(TAG, 'updateSearchItemData success');
} catch (error) {
LogUtil.error(`${TAG} updateSearchItemData error, message: ${error?.message}, code: ${error?.code}`);
HiSysEventUtil.searchReportEvent(TAG, `updateSearchItemData error: ${JSON.stringify(error)}`);
if (error.code === RDB_CORRUPTION_ERROR_CODE) {
HiSysEventUtil.reportDefaultFaultEvent(HiSysRdbEventGroup.EVENT_NAME,
HiSysRdbEventGroup.SETTINGS_DATA_RDB_CORRUPTION);
await super.restoreRdb();
}
rdbStore.rollBack();
}
}
async clearSearchData(): Promise<void> {
const rdbStore = await this.getRdbStore();
try {
await rdbStore.executeSql(SQL_DELETE_ITEM_INFO_TABLE);
LogUtil.info(`${TAG} clearSearchData successfully.`);
HiSysEventUtil.searchReportEvent(TAG, 'ClearSearchData success');
} catch (error) {
LogUtil.error(`${TAG} clearSearchata failed, message: ${error?.message}, code: ${error?.code}`);
HiSysEventUtil.searchReportEvent(TAG, `clearSearchData error: ${JSON.stringify(error)}`)
if (error.code === RDB_CORRUPTION_ERROR_CODE) {
HiSysEventUtil.reportDefaultFaultEvent(HiSysRdbEventGroup.EVENT_NAME,
HiSysRdbEventGroup.SETTINGS_DATA_RDB_CORRUPTION);
await super.restoreRdb();
}
rdbStore.rollBack();
}
}
async updateSearchItem(itemName: string, enable: boolean): Promise<void> {
if (CheckEmptyUtils.checkStrIsEmpty(itemName)) {
LogUtil.showError(TAG, 'updateSearchItem error, itemName is empty');
return;
}
try {
let valuesBucket: relationalStore.ValuesBucket = {
'enable': enable ? ENABLED_TRUE : ENABLED_FALSE
};
let conditions: Map<string, relationalStore.ValueType> = new Map();
conditions.set('itemName', itemName);
let result = await RdbTaskPool.getInstance().update(ITEMINFO_TABLE, conditions, valuesBucket);
LogUtil.showInfo(TAG, `search item updated changeRows: ${result}, itemName: ${itemName}, enable: ${enable}`);
} catch (err) {
LogUtil.showError(TAG, `updateSearchItem error: ${err?.message}`);
}
}
async updateSearchEntry(entryKey: string, enable: boolean): Promise<void> {
if (CheckEmptyUtils.checkStrIsEmpty(entryKey)) {
LogUtil.showError(TAG, 'updateSearchEntry error, entryKey is empty');
return;
}
try {
let valuesBucket: relationalStore.ValuesBucket = {
'enable': enable ? ENABLED_TRUE : ENABLED_FALSE
};
let conditions: Map<string, relationalStore.ValueType> = new Map();
conditions.set('entryKey', entryKey);
let result = await RdbTaskPool.getInstance().update(ITEMINFO_TABLE, conditions, valuesBucket);
LogUtil.showInfo(TAG, `search item updated changeRows: ${result}, entryKey: ${entryKey}, enable: ${enable}`);
} catch (err) {
LogUtil.showError(TAG, `updateSearchItem error: ${err?.message}`);
}
}
/* instrument ignore next */
async updateSearchItemByBundle(bundleName: string, enable: boolean): Promise<void> {
if (CheckEmptyUtils.checkStrIsEmpty(bundleName)) {
LogUtil.showError(TAG, 'updateSearchItemByBundle error, bundleName is empty');
return;
}
try {
let valuesBucket: relationalStore.ValuesBucket = {
'enable': enable ? ENABLED_TRUE : ENABLED_FALSE
};
let conditions: Map<string, relationalStore.ValueType> = new Map();
conditions.set('bundleName', bundleName);
let result = await RdbTaskPool.getInstance().update(ITEMINFO_TABLE, conditions, valuesBucket);
LogUtil.showDebug(TAG, `search item updated bundle: ${bundleName} changeRows: ${result}`);
} catch (error) {
LogUtil.showError(TAG, `updateSearchItemByBundle error, message: ${error?.message}, code: ${error?.code}`);
if (error.code === RDB_CORRUPTION_ERROR_CODE) {
HiSysEventUtil.reportDefaultFaultEvent(HiSysRdbEventGroup.EVENT_NAME,
HiSysRdbEventGroup.SETTINGS_DATA_RDB_CORRUPTION);
await super.restoreRdb();
}
}
}
async upgradeDb(upgradeSqlList: string[], latestRdbVersion: number): Promise<void> {
const rdbStore = await this.getRdbStore();
try {
rdbStore.beginTransaction();
for (const element of upgradeSqlList) {
await rdbStore.executeSql(element);
}
rdbStore.commit();
rdbStore.version = latestRdbVersion;
LogUtil.showInfo(TAG, `upgrade db success, newest version : ${rdbStore.version}`);
} catch (error) {
LogUtil.showError(TAG, `upgrade db failed, message: ${error?.message}, code: ${error?.code}`);
if (error.code === RDB_CORRUPTION_ERROR_CODE) {
HiSysEventUtil.reportDefaultFaultEvent(HiSysRdbEventGroup.EVENT_NAME,
HiSysRdbEventGroup.SETTINGS_DATA_RDB_CORRUPTION);
await super.restoreRdb();
}
rdbStore.rollBack();
}
}
async queryChildItems(itemName: string): Promise<string[]> {
if (CheckEmptyUtils.checkStrIsEmpty(itemName)) {
LogUtil.showError(TAG, 'queryChildItems error, itemName is empty');
return [];
}
let result: string = '';
try {
let conditions: Map<string, relationalStore.ValueType> = new Map();
conditions.set('itemName', itemName);
result = await RdbTaskPool.getInstance().queryChildItems(ITEMINFO_TABLE, conditions);
LogUtil.showDebug(TAG, `queryChildItems result: ${result}`);
} catch (err) {
LogUtil.showError(TAG, `queryChildItems error: ${err?.message}`);
return [];
}
return result.split(',');
}
/* instrument ignore next */
async deleteSearchItem(locale: string): Promise<void> {
if (CheckEmptyUtils.checkStrIsEmpty(locale)) {
LogUtil.showError(TAG, 'deleteSearchItem error, locale is empty');
return;
}
const rdbStore = await this.getRdbStore();
try {
rdbStore.beginTransaction();
const predicates = new relationalStore.RdbPredicates(ITEMINFO_TABLE);
predicates.equalTo('locale', locale);
let result = await rdbStore.delete(predicates);
rdbStore.commit();
LogUtil.showInfo(TAG, `delete search item: ${locale} changeRows: ${result}`);
} catch (error) {
LogUtil.showError(TAG,
`deleteSearchItem error, message: ${error?.message}, code: ${error?.code}, ${RDB_CORRUPTION_ERROR_CODE}, ${error?.code ===
RDB_CORRUPTION_ERROR_CODE}}`);
if (error?.code === RDB_CORRUPTION_ERROR_CODE) {
HiSysEventUtil.reportDefaultFaultEvent(HiSysRdbEventGroup.EVENT_NAME,
HiSysRdbEventGroup.SETTINGS_DATA_RDB_CORRUPTION);
await super.restoreRdb();
}
rdbStore.rollBack();
}
}
/**
* 查询搜索项的配置表
* @param itemName 配置项
* @param bundleName 包名
* @returns 详情
*/
async querySearchItemData(itemName: string[], bundleName?: string): Promise<ItemInfo[]> {
const rdbStore = await this.getRdbStore();
let itemInfoList: ItemInfo[] = [];
let resultSet: relationalStore.ResultSet | undefined;
try {
const predicates = new relationalStore.RdbPredicates(ITEMINFO_TABLE);
let curLocale: string = i18n.System.getSystemLocale();
predicates.equalTo('locale', curLocale).and().in('itemName', itemName);
if (bundleName) {
predicates.and().equalTo('bundleName', bundleName);
}
resultSet = await rdbStore.query(predicates);
while (resultSet?.goToNextRow()) {
const locale: string = resultSet.getString(resultSet.getColumnIndex('locale'));
const itemName: string = resultSet.getString(resultSet.getColumnIndex('itemName'));
const itemTitle: string = resultSet.getString(resultSet.getColumnIndex('itemTitle'));
const itemDescription: string = resultSet.getString(resultSet.getColumnIndex('itemDescription'));
const entryKey: string = resultSet.getString(resultSet.getColumnIndex('entryKey'));
const pageTitle: string = resultSet.getString(resultSet.getColumnIndex('pageTitle'));
const params: string = resultSet.getString(resultSet.getColumnIndex('params'));
const enable: boolean = resultSet.getLong(resultSet.getColumnIndex('enable')) === ENABLED_TRUE;
const icon: string = resultSet.getString(resultSet.getColumnIndex('icon'));
const alias: string = resultSet.getString(resultSet.getColumnIndex('alias'));
const childItems: string = resultSet.getString(resultSet.getColumnIndex('childItems'));
const path: string = resultSet.getString(resultSet.getColumnIndex('path'));
const bundleName: string = resultSet.getString(resultSet.getColumnIndex('bundleName'));
const checkType: string = resultSet.getString(resultSet.getColumnIndex('checkType'));
const checkKey: string = resultSet.getString(resultSet.getColumnIndex('checkKey'));
const checkValue: string = resultSet.getString(resultSet.getColumnIndex('checkValue'));
itemInfoList.push({
locale,
itemName,
itemTitle,
itemDescription,
entryKey,
pageTitle,
params,
enable,
icon,
alias,
childItems,
path,
bundleName,
checkType,
checkKey,
checkValue,
});
}
return itemInfoList;
} catch (error) {
LogUtil.error(`${TAG} query querySearchItemData message: ${error?.message}, code: ${error?.code}`);
if (error.code === RDB_CORRUPTION_ERROR_CODE) {
await super.restoreRdb();
}
return itemInfoList;
} finally {
resultSet?.close();
}
}
/* instrument ignore next */
async insertOrUpdateSearchItemData(itemInfo: ItemInfo): Promise<void> {
const rdbStore = await this.getRdbStore();
if (itemInfo) {
let resultSet: relationalStore.ResultSet | undefined;
try {
const predicates = new relationalStore.RdbPredicates(ITEMINFO_TABLE);
predicates.equalTo('itemName', itemInfo.itemName).and()
.equalTo('locale', itemInfo.locale)
.and().equalTo('bundleName', itemInfo.bundleName);
resultSet = await rdbStore.query(predicates);
if (resultSet.rowCount) {
await rdbStore.update(this.getDbBucketList(itemInfo), predicates);
LogUtil.info(`${TAG} insertOrUpdateSearchItemData success`);
return;
}
let result: number = await rdbStore.insert(ITEMINFO_TABLE, this.getDbBucketList(itemInfo));
LogUtil.info(`${TAG} insertOrUpdateSearchItemData result: ${result}`);
} catch (error) {
LogUtil.error(`${TAG} insertSearchHistoryData message: ${error?.message}, code: ${error?.code}`);
if (error.code === RDB_CORRUPTION_ERROR_CODE) {
await super.restoreRdb();
}
} finally {
resultSet?.close();
}
}
}
}
export default new SearchItemInfoManager();