* Copyright (c) Huawei Device 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 GridLayoutItemInfo from '../bean/GridLayoutItemInfo';
import { CommonConstants } from '../constants/CommonConstants';
import GridLayoutInfoColumns from './column/GridLayoutInfoColumns';
import rdb from '@ohos.data.relationalStore';
import { RdbStoreHelper } from '@ohos/frameworkwrapper/src/main/ets/service/db/RdbStoreHelper';
import { ArrayUtils, LogDomain, LogHelper, } from '@ohos/basicutils';
import { DeviceHelper } from '@ohos/frameworkwrapper';
const TAG: string = 'RdbSqlHelp';
const log: LogHelper = LogHelper.getLogHelper(LogDomain.HOME, TAG);
const RESULT_COLUMN_ARRAY: string[] = [
GridLayoutInfoColumns.ID,
GridLayoutInfoColumns.TYPE_ID,
GridLayoutInfoColumns.INFO_ID,
GridLayoutInfoColumns.BUNDLE_NAME,
GridLayoutInfoColumns.ABILITY_NAME,
GridLayoutInfoColumns.MODULE_NAME,
GridLayoutInfoColumns.APP_INDEX,
GridLayoutInfoColumns.SHORTCUT_ID,
GridLayoutInfoColumns.FILE_INO,
];
const QUERY_BATCH_COUNT: number = 1000;
export default class RdbSqlHelp {
public static getInstance(): RdbSqlHelp {
if (globalThis.RdbSqlHelp == null) {
globalThis.RdbSqlHelp = new RdbSqlHelp();
}
return globalThis.RdbSqlHelp;
}
* 批量查询数据库并在本地建立数据和_id的映射关系,每次查询数量上限为QUERY_BATCH_COUNT
*
* @param rdbStoreHelper 数据库操作类
* @param tableName 需要查询的表名
* @param sqlItemData 映射关系存储集合
* @param startId 批量查询的起始id
*/
public async getAllDataByBatchSql(rdbStoreHelper: RdbStoreHelper, tableName: string, sqlItemData: SqlItemData,
startId: number): Promise<void> {
log.showInfo('getAllDataByBatchSql start, startId: %{public}d', startId);
const predicates = new rdb.RdbPredicates(tableName);
if (!DeviceHelper.isPhoneOrPad()) {
predicates.notEqualTo(GridLayoutInfoColumns.CONTAINER, CommonConstants.CONTAINER_SMARTDOCK).and();
}
predicates.greaterThanOrEqualTo(GridLayoutInfoColumns.ID, startId)
.orderByAsc(GridLayoutInfoColumns.ID)
.limitAs(QUERY_BATCH_COUNT);
let queryResult: rdb.ResultSet | undefined = await rdbStoreHelper.query(predicates, RESULT_COLUMN_ARRAY);
if (queryResult && queryResult.rowCount > 0) {
while (queryResult.goToNextRow()) {
let key: string = this.getItemDataKey(queryResult);
let id: number = queryResult.getLong(queryResult.getColumnIndex(GridLayoutInfoColumns.ID));
sqlItemData.keyMap.set(key, id);
}
}
if (queryResult?.rowCount === QUERY_BATCH_COUNT) {
await this.getAllDataByBatchSql(rdbStoreHelper, tableName, sqlItemData, startId + QUERY_BATCH_COUNT);
}
queryResult?.close();
}
private getItemDataKey(result: rdb.ResultSet) : string {
let key: string = '';
let type: number = result.getLong(result.getColumnIndex(GridLayoutInfoColumns.TYPE_ID));
if (type === CommonConstants.TYPE_APP || type === CommonConstants.TYPE_SHORTCUT_ICON) {
key = type + result.getString(result.getColumnIndex(GridLayoutInfoColumns.BUNDLE_NAME)) +
result.getString(result.getColumnIndex(GridLayoutInfoColumns.ABILITY_NAME)) +
result.getString(result.getColumnIndex(GridLayoutInfoColumns.MODULE_NAME)) +
result.getLong(result.getColumnIndex(GridLayoutInfoColumns.APP_INDEX)) +
result.getString(result.getColumnIndex(GridLayoutInfoColumns.SHORTCUT_ID));
} else if (type === CommonConstants.TYPE_FILE_FOLDER) {
key = type + result.getString(result.getColumnIndex(GridLayoutInfoColumns.FILE_INO));
} else if (type === CommonConstants.TYPE_FOLDER || type === CommonConstants.TYPE_CARD ||
type === CommonConstants.TYPE_FORM_STACK) {
key = type + result.getString(result.getColumnIndex(GridLayoutInfoColumns.INFO_ID));
}
return key;
}
public getItemKey(item: GridLayoutItemInfo): string {
let key: string = '';
if (item.typeId === CommonConstants.TYPE_APP || item.typeId === CommonConstants.TYPE_SHORTCUT_ICON) {
key = `${item.typeId}${item.bundleName}${item.abilityName ?? ''}${item.moduleName ??
''}${item.appIndex ?? 0}${item.shortcutId ?? ''}`;
} else if (item.typeId === CommonConstants.TYPE_FOLDER) {
key = `${item.typeId}${item.folderId}`;
} else if (item.typeId === CommonConstants.TYPE_CARD) {
key = `${item.typeId}${item.cardId}`;
} else if (item.typeId === CommonConstants.TYPE_FORM_STACK) {
key = `${item.typeId}${item.formStackId}`;
} else if (item.typeId === CommonConstants.TYPE_FILE_FOLDER) {
key = `${item.typeId}${item.ino}`;
}
return key;
}
public getUpdateSqlDataSet(sqlItemData: SqlItemData, container: number | undefined): UpdateSqlDataSet {
const updateSqlDataSet: UpdateSqlDataSet = new UpdateSqlDataSet();
sqlItemData.updateList.forEach(item => {
let itemKey: string = this.getItemKey(item);
let id: number | undefined = sqlItemData.keyMap.get(itemKey);
if (id === undefined) {
return;
}
updateSqlDataSet.idArray.push(id);
updateSqlDataSet.getUpdateData(GridLayoutInfoColumns.ROW)?.params.set(id, item.row);
updateSqlDataSet.getUpdateData(GridLayoutInfoColumns.COLUMN)?.params.set(id, item.column);
updateSqlDataSet.getUpdateData(GridLayoutInfoColumns.PAGE_INDEX)?.params.set(id, item.page);
updateSqlDataSet.getUpdateData(GridLayoutInfoColumns.CONTAINER)?.params.set(id,
container ? container : (item.container ?? CommonConstants.CONTAINER_DESKTOP));
updateSqlDataSet.getUpdateData(GridLayoutInfoColumns.WIDTH)?.params.set(id, item.area[0]);
updateSqlDataSet.getUpdateData(GridLayoutInfoColumns.HEIGHT)?.params.set(id, item.area[1]);
updateSqlDataSet.getUpdateData(GridLayoutInfoColumns.PORTRAIT_ROW)?.params.set(id, item.portraitRow ?? 0);
updateSqlDataSet.getUpdateData(GridLayoutInfoColumns.PORTRAIT_COLUMN)?.params.set(id, item.portraitColumn ?? 0);
updateSqlDataSet.getUpdateData(GridLayoutInfoColumns.PORTRAIT_PAGE_INDEX)?.params.set(id, item.portraitPage ?? 0);
updateSqlDataSet.getUpdateData(GridLayoutInfoColumns.LANDSCAPE_ROW)?.params.set(id, item.landscapeRow ?? 0);
updateSqlDataSet.getUpdateData(GridLayoutInfoColumns.LANDSCAPE_COLUMN)?.params.set(id, item.landscapeColumn ?? 0);
updateSqlDataSet.getUpdateData(GridLayoutInfoColumns.LANDSCAPE_PAGE_INDEX)?.params.set(id, item.landscapePage ?? 0);
if (item.typeId === CommonConstants.TYPE_FILE_FOLDER) {
updateSqlDataSet.getUpdateData(GridLayoutInfoColumns.URI)?.params.set(id, item.uri ?? '');
updateSqlDataSet.getUpdateData(GridLayoutInfoColumns.INFO_NAME)?.params.set(id, item.fileFolderName ?? '');
}
});
return updateSqlDataSet;
}
public getBatchUpdateSql(updateSqlDataSet: UpdateSqlDataSet, startIndex: number, tableName: string,
updateCount: number): string {
log.showInfo('getBatchUpdateSql startIndex = %{public}d', startIndex);
if (startIndex >= updateSqlDataSet.idArray.length) {
return '';
}
let sqlStr: StringBuilder = new StringBuilder();
sqlStr.append(`UPDATE ${tableName} SET`);
let endIndex: number = startIndex + updateCount;
sqlStr.append(updateSqlDataSet.getUpdateSql(startIndex, endIndex));
sqlStr.append(` WHERE ${GridLayoutInfoColumns.ID} IN (${updateSqlDataSet.getIds(startIndex, endIndex)})`);
return sqlStr.toString();
}
}
export class SqlItemData {
keyMap: Map<string, number>;
updateList: GridLayoutItemInfo[];
insertList: GridLayoutItemInfo[];
constructor() {
this.keyMap = new Map();
this.updateList = [];
this.insertList = [];
}
}
* 用于生成批量更新数据库sql语句的数据集合类,sql语句格式如下:
* update table
* set columName1 = case id
* when 1 then %value
* when 2 then %value
* when 3 then %value
* end,
* ...
* columNameX = case id
* when 1 then %value
* when 2 then %value
* when 3 then %value
* end,
* where id in (1, 2, 3)
* 每一个列名的when语句集合生成通过UpdateSqlData来控制
* dataMap中key为columName,value为when语句的数据集合UpdateSqlData,则用于生成主体语句
*/
export class UpdateSqlDataSet {
idArray: number[];
private dataMap: Map<string, UpdateSqlData> = new Map();
constructor() {
this.idArray = [];
let updateRowData: UpdateSqlData = new UpdateSqlData(GridLayoutInfoColumns.ROW);
this.dataMap.set(GridLayoutInfoColumns.ROW, updateRowData);
let updateColumnData: UpdateSqlData = new UpdateSqlData(GridLayoutInfoColumns.COLUMN);
this.dataMap.set(GridLayoutInfoColumns.COLUMN, updateColumnData);
let updatePageData: UpdateSqlData = new UpdateSqlData(GridLayoutInfoColumns.PAGE_INDEX);
this.dataMap.set(GridLayoutInfoColumns.PAGE_INDEX, updatePageData);
let updateContainerData: UpdateSqlData = new UpdateSqlData(GridLayoutInfoColumns.CONTAINER);
this.dataMap.set(GridLayoutInfoColumns.CONTAINER, updateContainerData);
let updateWidthData: UpdateSqlData = new UpdateSqlData(GridLayoutInfoColumns.WIDTH);
this.dataMap.set(GridLayoutInfoColumns.WIDTH, updateWidthData);
let updateHeightData: UpdateSqlData = new UpdateSqlData(GridLayoutInfoColumns.HEIGHT);
this.dataMap.set(GridLayoutInfoColumns.HEIGHT, updateHeightData);
let updateUriData: UpdateSqlData = new UpdateSqlData(GridLayoutInfoColumns.URI);
this.dataMap.set(GridLayoutInfoColumns.URI, updateUriData);
let updateInfoNameData: UpdateSqlData = new UpdateSqlData(GridLayoutInfoColumns.INFO_NAME);
this.dataMap.set(GridLayoutInfoColumns.INFO_NAME, updateInfoNameData);
let updatePortraitRowData: UpdateSqlData = new UpdateSqlData(GridLayoutInfoColumns.PORTRAIT_ROW);
this.dataMap.set(GridLayoutInfoColumns.PORTRAIT_ROW, updatePortraitRowData);
let updatePortraitColumnData: UpdateSqlData = new UpdateSqlData(GridLayoutInfoColumns.PORTRAIT_COLUMN);
this.dataMap.set(GridLayoutInfoColumns.PORTRAIT_COLUMN, updatePortraitColumnData);
let updatePortraitPageData: UpdateSqlData = new UpdateSqlData(GridLayoutInfoColumns.PORTRAIT_PAGE_INDEX);
this.dataMap.set(GridLayoutInfoColumns.PORTRAIT_PAGE_INDEX, updatePortraitPageData);
let updateLandscapeRowData: UpdateSqlData = new UpdateSqlData(GridLayoutInfoColumns.LANDSCAPE_ROW);
this.dataMap.set(GridLayoutInfoColumns.LANDSCAPE_ROW, updateLandscapeRowData);
let updateLandscapeColumnData: UpdateSqlData = new UpdateSqlData(GridLayoutInfoColumns.LANDSCAPE_COLUMN);
this.dataMap.set(GridLayoutInfoColumns.LANDSCAPE_COLUMN, updateLandscapeColumnData);
let updateLandscapePageData: UpdateSqlData = new UpdateSqlData(GridLayoutInfoColumns.LANDSCAPE_PAGE_INDEX);
this.dataMap.set(GridLayoutInfoColumns.LANDSCAPE_PAGE_INDEX, updateLandscapePageData);
}
public getUpdateData(columnName: string) : UpdateSqlData | undefined {
return this.dataMap.get(columnName);
}
public getIds(startIndex: number, endIndex: number): string {
if (ArrayUtils.isEmpty(this.idArray)) {
return '';
}
let idsStr: StringBuilder = new StringBuilder();
this.idArray.slice(startIndex, endIndex).forEach((id) => {
idsStr.append(`${id},`);
});
let ids: string = idsStr.toString();
return ids.substring(0, ids.length - 1);
}
public getUpdateSql(startIndex: number, endIndex: number): string {
let sqlStr: StringBuilder = new StringBuilder();
this.dataMap.forEach((data) => {
if (data.params.size === 0) {
return;
}
sqlStr.append(` ${data.columnName} = CASE ${GridLayoutInfoColumns.ID}`);
this.idArray.slice(startIndex, endIndex).forEach((id) => {
sqlStr.append(data.getSqlStr(id));
});
sqlStr.append(` ELSE ${data.columnName} END,`);
});
let sql: string = sqlStr.toString();
return sql.substring(0, sql.length - 1);
}
}
export class UpdateSqlData {
columnName: string;
params: Map<number, string | number>;
constructor(columnName: string) {
this.columnName = columnName;
this.params = new Map();
}
public getSqlStr(id: number): string {
if (this.params.has(id)) {
const value = this.params.get(id) ?? '';
if (value !== '' && typeof value === 'string') {
return ` WHEN ${id} THEN '${value}'`;
} else {
return ` WHEN ${id} THEN ${value}`;
}
}
return '';
}
}
class StringBuilder {
private strings: string[];
public constructor() {
this.strings = [];
}
public append(str: string): StringBuilder {
this.strings.push(str);
return this;
}
public toString(): string {
return this.strings.join('');
}
}