/*
* 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 common from '@ohos.app.ability.common';
import rdb from '@ohos.data.relationalStore';
import { BusinessError } from '@ohos.base';
import { ValuesBucket } from '@ohos.data.ValuesBucket';
import contextConstant from '@ohos.app.ability.contextConstant';
import securityLabel from '@ohos.file.securityLabel';
import LogUtils from '../utils/LogUtils';
import { ArrayUtil } from '../utils/ArrayUtil';
import { Account } from '../contract/Account';
import DbConstants from '../DbConstants';
import DatabaseUtils from '../utils/DatabaseUtils';
import { SystemModeController } from '../utils/SystemModeController';
import { Data } from '../contract/Data';
import { LATEST_CHANNEL_STORE_VERSION } from '../SqlConstants';
/**
* 双升单,单框架insert处理dbHelper
*/
export class BaseSingleRdbInsertHelper {
private readonly logTag: string = '';
constructor(logTag: string) {
this.logTag = `[${logTag}::BaseSingleRdbInsertHelper]`;
}
public async getRdbStoreHelper(context: common.Context, dbName: string,
isSupportSearch: boolean): Promise<rdb.RdbStore | undefined> {
LogUtils.i(this.logTag, 'getRdbStoreHelper start');
if (context === undefined || context === null) {
LogUtils.w(this.logTag, 'getRdbStoreHelper failed context is empty');
return undefined;
}
//单框架开本地联系人库指定路径EL2
context.area = contextConstant.AreaMode.EL2;
let rdbStoreHelper: rdb.RdbStore | undefined = undefined;
try {
// 设置文件的数据等级为s3
await securityLabel.setSecurityLabel('/data/storage/el2/database/rdb/contacts.db', 's3').then(() => {
LogUtils.i(this.logTag, 'Succeeded in setSecurityLabeling contacts.db s3');
}).catch((err: BusinessError) => {
LogUtils.e(this.logTag, `Failed to setSecurityLabel. Code: ${err.code}, message: ${err.message}`);
});
const CONFIG: rdb.StoreConfig = {
name: dbName,
//双升单连接单框架db,改为正确等级S3
securityLevel: rdb.SecurityLevel.S3,
isSearchable: isSupportSearch,
autoCleanDirtyData: false,
customDir: '../../rdb',
allowRebuild: true
};
rdbStoreHelper = await rdb.getRdbStore(context, CONFIG);
if (rdbStoreHelper != null) { // 如果开库成功,
let rebuilt: number = rdbStoreHelper.rebuilt;
LogUtils.i(this.logTag, `getRdbStoreContacts, rebuilt:${rebuilt}`);
if (rebuilt == rdb.RebuildType.REBUILT ) { // 如果进行了重建
await rdbStoreHelper.restore('contacts.db.bak', (err) => {
if (err) {
LogUtils.e(this.logTag, `getRdbStoreContacts, Restore failed, code is ${err.code},message is ${err.message}`);
return;
}
LogUtils.i(this.logTag, `getRdbStoreContacts, Restore success.`);
}); // 则进行恢复
} else {
// 没有重建,什么也不做
LogUtils.i(this.logTag, `getRdbStoreContacts, No rebuilt`);
}
} else {
//开库失败 进行恢复
LogUtils.e(this.logTag, `getRdbStoreContacts, GetRdbStore err, rdbStoreHelper is null, skip rebuilt. `);
await (rdbStoreHelper as rdb.RdbStore).restore('contacts.db.bak', (err) => {
if (err) {
LogUtils.e(this.logTag, `Restore failed,code is ${err.code},message is ${err.message}`);
return;
}
LogUtils.i(this.logTag, `Restore success.`);
})
}
const curVersion = rdbStoreHelper.version;
if (curVersion === 0) {
LogUtils.i(this.logTag, 'initDB end, contact db version is:0, start exec ddl');
await this.createTable(context, rdbStoreHelper);
await this.createViewTable(context, rdbStoreHelper);
await this.createTableRelative(rdbStoreHelper);
rdbStoreHelper.version = LATEST_CHANNEL_STORE_VERSION;
} else {
LogUtils.i(this.logTag, `initDB end, contact db version is:${curVersion}, skip exec ddl`);
}
if (rdbStoreHelper != null && dbName === DbConstants.NEW_DATABASE_NAME) {
// 开库成功之后,设置 distributedTables
let distributedConfig: rdb.DistributedConfig = {
autoSync: false,
asyncDownloadAsset: true,
enableCloud: SystemModeController.getInstance().getIsEnableContactCloudSync()
};
let tablesToSync: string[] = ['cloud_raw_contact', 'cloud_groups'];
await rdbStoreHelper.setDistributedTables(tablesToSync, rdb.DistributedType.DISTRIBUTED_CLOUD,
distributedConfig);
LogUtils.w(this.logTag, 'getRdbStoreHelper,setDistributedTables success.');
}
} catch (error) {
LogUtils.w(this.logTag, `getRdbStoreHelper failed,code is ${error.code},message is ${error.message}`);
}
return Promise.resolve(rdbStoreHelper);
}
protected async initDB(context: common.Context): Promise<rdb.RdbStore | undefined> {
LogUtils.i(this.logTag, 'BaseSingleRdbInsertHelper initDB start');
return Promise.resolve(undefined);
}
/**
* Batch insert data into table contact_type
*
* @param context to get RdbStore
* @param contactsDataList which data to insert
* @returns the number of successful insertions
*/
public async insertContactType(context: common.Context): Promise<number> {
let rdbStoreHelper: rdb.RdbStore | undefined = await this.initDB(context);
if (rdbStoreHelper === undefined) {
return Promise.resolve(-1);
}
let typeDataArray: ValuesBucket[] = [];
DbConstants.SIMPLE_TYPE.forEach((type, index) => {
let pushBody : Record<string, string | number> = {};
pushBody[Data.NEW_ID] = index + 1;
pushBody[Data.CONTENT_TYPE] = type;
typeDataArray.push(pushBody);
});
let ret = -1;
LogUtils.i(this.logTag, 'insertType start');
try {
rdbStoreHelper.beginTransaction();
ret = await rdbStoreHelper.batchInsert('contact_type', typeDataArray);
rdbStoreHelper.commit();
} catch (error) {
rdbStoreHelper.rollBack();
LogUtils.e(this.logTag, 'insertType error');
}
return ret;
}
/**
* Insert data into table account
*
* @param context to get RdbStore
* @param id which data to insert
* @returns the number of successful insertions
*/
public async insertPhoneAccount(context: common.Context, id: number): Promise<number> {
let rdbStoreHelper: rdb.RdbStore | undefined = await this.initDB(context);
if (rdbStoreHelper === undefined) {
return Promise.resolve(-1);
}
let ret = -1;
const values: ValuesBucket = {};
values[Account.NEW_ID] = id;
values[Account.ACCOUNT_NAME] = 'phone';
values[Account.ACCOUNT_TYPE] = 'com.ohos.contacts';
try {
ret = await rdbStoreHelper.insert(DbConstants.NEW_ACCOUNT_TABLE_NAME, values);
} catch (error) {
LogUtils.e(this.logTag, 'insertPhoneAccount error');
}
return Promise.resolve(ret);
}
/**
* Batch insert data into contact
*
* @param context to get RdbStore
* @param contactsDataList which data to insert
* @param tableName which table name to insert
* @returns the number of successful insertions
*/
public async insertBatchData(context: common.Context,
contactsDataList: ValuesBucket[], tableName: string): Promise<number> {
if (ArrayUtil.isEmpty(contactsDataList)) {
LogUtils.e(this.logTag, 'contactsDataList is NULL');
return Promise.resolve(-1);
}
let rdbStoreHelper: rdb.RdbStore | undefined = await this.initDB(context);
if (rdbStoreHelper === undefined) {
return Promise.resolve(-1);
}
let ret = -1;
LogUtils.i(this.logTag, 'insertBatchData start');
try {
rdbStoreHelper.beginTransaction();
ret = await rdbStoreHelper.batchInsert(tableName, contactsDataList);
rdbStoreHelper.commit();
} catch (error) {
rdbStoreHelper.rollBack();
LogUtils.e(this.logTag, `insertBatchData err,msg:${error.message}`);
}
return ret;
}
private async createTable(context: common.Context, rdbStore: rdb.RdbStore) {
for (const tableName of DbConstants.CREATE_CONTACT_TABLE_MAP.keys()) {
const createTableSql = DbConstants.CREATE_CONTACT_TABLE_MAP.get(tableName);
try {
await DatabaseUtils.executeSqlFuncWithRetry(() => rdbStore.executeSql(createTableSql!));
} catch (error) {
LogUtils.e(this.logTag, `Create table error: code: ${error.code}, message: ${error.message}`);
}
}
LogUtils.w(this.logTag, `Create table end`);
}
private async createViewTable(context: common.Context, rdbStore: rdb.RdbStore) {
for (const viewName of DbConstants.CREATE_CONTACT_VIEW_MAP.keys()) {
const createViewSql = DbConstants.CREATE_CONTACT_VIEW_MAP.get(viewName);
try {
await DatabaseUtils.executeSqlFuncWithRetry(() => rdbStore.executeSql(createViewSql!));
} catch (error) {
LogUtils.e(this.logTag, `Create view table error: code: ${error.code}, message: ${error.message}`);
}
}
LogUtils.w(this.logTag, `Create view table end`);
}
/**
* 创建索引或触发器
* @param rdbStore
*/
private async createTableRelative(rdbStore: rdb.RdbStore) {
for (const sql of DbConstants.CREATE_CONTACT_TABLE_RELATIVE) {
try {
await DatabaseUtils.executeSqlFuncWithRetry(() => rdbStore.executeSql(sql));
} catch (error) {
LogUtils.e(this.logTag, `Create table relative error: code: ${error.code}, message: ${error.message}`);
}
}
LogUtils.w(this.logTag, `Create table relative end`);
}
}