1/** 2 * @file Describe the file 3 * Copyright (c) 2023 Huawei Device Co., Ltd. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17import data_rdb from '@ohos.data.relationalStore'; 18import { ValuesBucket } from '@ohos.data.ValuesBucket'; 19import dataSharePredicates from '@ohos.data.dataSharePredicates'; 20 21import { Log } from "@ohos/common/src/main/ets/utils/Log"; 22import { isEmptyStr } from '@ohos/common/src/main/ets/utils/TextUtils'; 23import { isContainsOneOfKeys } from '@ohos/common/src/main/ets/utils/ValuesUtils'; 24import { getBundleNameByUri } from '@ohos/common/src/main/ets/utils/UrlUtils'; 25 26import { EventColumns, UPDATE_INSTANCES_COLUMNS } from '@ohos/datastructure/src/main/ets/events/EventColumns'; 27import { Events } from '@ohos/datastructure/src/main/ets/events/Events'; 28import { InstancesColumns } from '@ohos/datastructure/src/main/ets/instances/InstancesColumns'; 29 30import { notifyProviderChange, OPERATION_UNKNOWN, } from '../../commonevents/notify/ProviderChangeNotifier'; 31import { DefaultProcessor } from "./../DefaultProcessor"; 32import { ErrorCode } from '../../constants/ErrorCode'; 33import { deleteAllInstances, expandAllByRange, expandOneInRange } from './InstanceExpandHelper'; 34import { generateInstancesQuerySql } from './InstancesQuerySqlGenerator'; 35import { isInExpandedRange, updateExpandedRange, getExpandedBegin, getExpandedEnd } from "./ExpandRangeManager"; 36import { InstancesQueryParams, parseParamsFromUri, isValidQueryParams } from './InstanceQueryParams'; 37 38const TAG = "InstancesProcessor"; 39 40/** 41 * the instances table processor 42 * 43 * @since 2022-05-28 44 */ 45export class InstancesProcessor extends DefaultProcessor { 46 async insertByHighAuthority(rdbStore, uri: string, values, callback) { 47 Log.warn(TAG, 'not support insert operation'); 48 const err = { 49 code: ErrorCode.UN_SUPPORT_OPERATION, 50 name: 'UnSupportedOperationException', 51 message: 'Instances Table not support insert operation' 52 }; 53 callback(err, 0); 54 } 55 56 async insertByLowAuthority(rdbStore, uri: string, values, callback) { 57 this.insertByHighAuthority(rdbStore, uri, values, callback); 58 } 59 60 async deleteByHighAuthority(rdbStore, uri: string, predicates, callback) { 61 Log.warn(TAG, 'not support delete operation'); 62 const err = { 63 code: ErrorCode.UN_SUPPORT_OPERATION, 64 name: 'UnSupportedOperationException', 65 message: 'Instances Table not support delete operation' 66 }; 67 callback(err, 0); 68 } 69 70 async deleteByLowAuthority(rdbStore, uri: string, predicates, callback) { 71 this.deleteByHighAuthority(rdbStore, uri, predicates, callback); 72 } 73 74 async updateByHighAuthority(rdbStore, uri: string, values, predicates, callback) { 75 Log.warn(TAG, 'not support update operation'); 76 const err = { 77 code: ErrorCode.UN_SUPPORT_OPERATION, 78 name: 'UnSupportedOperationException', 79 message: 'Instances Table not support update operation' 80 }; 81 callback(err, 0); 82 } 83 84 async updateByLowAuthority(rdbStore, uri: string, values, predicates, callback) { 85 this.updateByHighAuthority(rdbStore, uri, values, predicates, callback); 86 } 87 88 async queryByHighAuthority(rdbStore, uri: string, columns: Array<string>, predicates, callback) { 89 const callerName = null; 90 this.queryByInstanceUri(rdbStore, uri, columns, callerName, callback); 91 } 92 93 async queryByLowAuthority(rdbStore, uri: string, columns: Array<string>, predicates, callback) { 94 const callerName = getBundleNameByUri(uri); 95 this.queryByInstanceUri(rdbStore, uri, columns, callerName, callback); 96 } 97 98 /** 99 * 解析 uri,根据 uri 进行 Instance 的联表查询 100 * 101 * @param rdbStore rdb数据库 102 * @param uri DataShare的uri,包含查询参数 103 * @param columns 查询的列名 104 * @param callerName 调用方app的bundle_name 105 * @param callback 回调方法 106 */ 107 async queryByInstanceUri(rdbStore, uri: string, columns: Array<string>, callerName, callback) { 108 const params: InstancesQueryParams = parseParamsFromUri(uri); 109 if (!isValidQueryParams(params)) { 110 const err = { 111 code: ErrorCode.ILLEGAL_ARGUMENT_ERROR, 112 name: 'IllegalArgumentError', 113 message: 'query Instances must has begin&end or searchText params like ?begin=${begin}&end=${end}' + 114 '&searchText=${searchText}' 115 }; 116 callback(err, null); 117 return; 118 } 119 if (params.isValidBeginEnd()) { 120 await acquireExpandAll(rdbStore, params.getBegin(), params.getEnd()); 121 } 122 doInstancesQuery(rdbStore, columns, params, callerName, callback); 123 } 124} 125 126/** 127 * 请求扩展Instances 128 * 1.在已扩展范围内,则不扩展 129 * 2.不在已扩展范围内,则按未扩展部分扩展全部 130 * 131 * @param begin 请求扩展的开始时间 132 * @param end 请求扩展的结束时间 133 */ 134export async function acquireExpandAll(rdbStore: data_rdb.RdbStore, acquireBegin: number, acquireEnd: number) { 135 Log.info(TAG, `acquireExpandAll begin from ${acquireBegin} to ${acquireEnd}`); 136 const isInRange = await isInExpandedRange(acquireBegin, acquireEnd); 137 if (isInRange) { 138 Log.info(TAG, `acquireExpandAll no need to expand`); 139 return; 140 } 141 let expandedBegin = await getExpandedBegin(); 142 let expandedEnd = await getExpandedEnd(); 143 Log.info(TAG, `acquireExpandAll expanded range:${expandedBegin}/${expandedEnd}`); 144 145 let shouldSendBroadcast: boolean = false; 146 if (expandedEnd === 0) { 147 Log.info(TAG, "acquireExpandAll first expand"); 148 await deleteAllInstances(rdbStore); 149 let isSuccess = await expandAllByRange(rdbStore, acquireBegin, acquireEnd); 150 if (isSuccess) { 151 Log.info(TAG, `expandAllByRange successful from ${acquireBegin} to ${acquireEnd}`); 152 updateExpandedRange(acquireBegin, acquireEnd); 153 expandedBegin = acquireBegin; 154 expandedEnd = acquireEnd; 155 shouldSendBroadcast = true; 156 } 157 } 158 159 // 处理比已扩展时间早的部分 160 if (acquireBegin < expandedBegin) { 161 let isSuccess = await expandAllByRange(rdbStore, acquireBegin, expandedBegin); 162 if (isSuccess) { 163 Log.info(TAG, `expandAllByRange successful from ${acquireBegin} to ${expandedBegin}`); 164 updateExpandedRange(acquireBegin, expandedEnd); 165 expandedBegin = acquireBegin; 166 shouldSendBroadcast = true; 167 } 168 } 169 170 // 处理比已扩展时间晚的部分 171 if (acquireEnd > expandedEnd) { 172 let isSuccess = await expandAllByRange(rdbStore, expandedEnd, acquireEnd); 173 if (isSuccess) { 174 Log.info(TAG, `expandAllByRange successful from ${expandedEnd} to ${acquireEnd}`); 175 updateExpandedRange(expandedBegin, acquireEnd); 176 expandedEnd = acquireEnd; 177 shouldSendBroadcast = true; 178 } 179 } 180 Log.info(TAG, `acquireExpandAll end from ${acquireBegin} to ${acquireEnd}`); 181 182 if (shouldSendBroadcast) { 183 notifyProviderChange(InstancesColumns.TABLE_NAME, OPERATION_UNKNOWN); 184 } 185} 186 187/** 188 * 请求扩展单个日程,用于日程创建/更新时 189 * 190 * @param eventId 日程ID 191 * @param values ValuesBucket数据(创建时)或Events数据(更新时) 192 */ 193export async function acquireExpandOne(rdbStore, rowId: number, values: ValuesBucket | Events) { 194 if (values === null || values === undefined) { 195 Log.error(TAG, 'acquireExpandOne get invalid params'); 196 return; 197 } 198 const expandedBegin = await getExpandedBegin(); 199 const expandedEnd = await getExpandedEnd(); 200 let event: Events; 201 if (values instanceof Events) { 202 event = values; 203 } else { 204 event = new Events(); 205 event.id = rowId; 206 parseEventsFromValues(values, event); 207 } 208 209 // 对于单个日程,仅对已全局扩展的时间范围内处理 210 let isSuccess = expandOneInRange(rdbStore, event, expandedBegin, expandedEnd); 211 if (isSuccess) { 212 notifyProviderChange(InstancesColumns.TABLE_NAME, OPERATION_UNKNOWN); 213 } else { 214 Log.warn(TAG, "expandOneByRange failed"); 215 } 216} 217 218/** 219 * 请求刷新一条Event的Instances 220 * 221 * @param rdbStore rdb数据库 222 * @param eventId 日程ID 223 * @param event 日程数据信息 224 */ 225export async function acquireUpdateOne(rdbStore: data_rdb.RdbStore, eventId: number, event: Events) { 226 const predicate = new dataSharePredicates.DataSharePredicates(); 227 predicate.equalTo(InstancesColumns.EVENT_ID, eventId); 228 await rdbStore.delete(InstancesColumns.TABLE_NAME, predicate); 229 acquireExpandOne(rdbStore, eventId, event); 230} 231 232/** 233 * 是否需要刷新Instances表,根据values内是否包含dtstart、rrule等关键字段来判断是否需要刷新Instances 234 * 235 * @param values 变更的values,以此判断是否需要刷新 236 * @return true 需要刷新; false 不需要刷新 237 */ 238export function isNeedRefreshInstances(values: ValuesBucket): boolean { 239 if (values === null || values === undefined) { 240 return false; 241 } 242 return isContainsOneOfKeys(values, UPDATE_INSTANCES_COLUMNS); 243} 244 245function parseEventsFromValues(values, event: Events): void { 246 event.dtStart = values[EventColumns.DTSTART]; 247 event.dtEnd = values[EventColumns.DTEND]; 248 event.rRule = values[EventColumns.RRULE]; 249 event.rDate = values[EventColumns.RDATE]; 250 event.exRule = values[EventColumns.EXRULE]; 251 event.exDate = values[EventColumns.EXDATE]; 252 event.allDay = values[EventColumns.ALLDAY]; 253 event.eventTimeZone = values[EventColumns.EVENT_TIMEZONE]; 254 event.originalId = values[EventColumns.ORIGINAL_ID]; 255 event.syncId = values[EventColumns.SYNC_ID]; 256 event.originalSyncId = values[EventColumns.ORIGINAL_SYNC_ID]; 257 event.lastDate = values[EventColumns.LAST_DATE]; 258 event.originalInstanceTime = values[EventColumns.ORIGINAL_INSTANCE_TIME]; 259 event.creator = values[EventColumns.CREATOR]; 260} 261 262function doInstancesQuery(rdbStore, columns: Array<string>, params: InstancesQueryParams, callerName, callback): void { 263 const sql = generateInstancesQuerySql(columns, params, callerName); 264 if (isEmptyStr(sql)) { 265 Log.error(TAG, `generate empty sql, the params maybe invalid`); 266 return; 267 } 268 Log.info(TAG, `instances query sql=${sql}`); 269 try { 270 rdbStore.querySql(sql, null, function (err, resultSet) { 271 callback(err, resultSet); 272 }) 273 } catch (err) { 274 Log.error(TAG, `doInstancesQuery querySql get err:${err?.message}, SQL:${sql}`); 275 } 276}