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 dataSharePredicates from '@ohos.data.dataSharePredicates'; 19import { BusinessError } from '@ohos.base'; 20import { ValueType } from '@ohos.data.ValuesBucket'; 21 22import { Log } from "@ohos/common/src/main/ets/utils/Log"; 23import { hasNoError } from '@ohos/common/src/main/ets/utils/ErrorUtils'; 24import { getBundleNameByUri } from '@ohos/common/src/main/ets/utils/UrlUtils'; 25 26import { Calendars } from '@ohos/datastructure/src/main/ets/calendars/Calendars'; 27import { APP_NAME } from '@ohos/datastructure/src/main/ets/calendars/CalendarsColumns'; 28import { CalendarsIndexes, parseCalendarsIndexes } from '@ohos/datastructure/src/main/ets/calendars/CalendarsIndexes'; 29import { CalendarsColumns } from '@ohos/datastructure/src/main/ets/calendars/CalendarsColumns'; 30import { EventColumns, UPDATE_INSTANCES_COLUMNS } from '@ohos/datastructure/src/main/ets/events/EventColumns'; 31import { Events } from '@ohos/datastructure/src/main/ets/events/Events'; 32import { EventIndexes, parseIndexes } from '@ohos/datastructure/src/main/ets/events/EventIndexes'; 33import { parseCalendars } from '@ohos/datastructure/src/main/ets/calendars/CalendarsParser'; 34import { parseEvents } from '@ohos/datastructure/src/main/ets/events/EventParser'; 35 36import { ErrorCode } from '../../constants/ErrorCode'; 37import { DefaultProcessor } from "./../DefaultProcessor"; 38import { initValueCreator, initPredicateCreator, deleteValueCreator } from '../DatabaseProcessorHelper'; 39import { acquireExpandOne, isNeedRefreshInstances, acquireUpdateOne } from '../instances/InstancesProcessor'; 40 41const TAG: string = "EventsProcessor"; 42 43/** 44 * the Events table processor 45 * 46 * @since 2022-06-24 47 */ 48export class EventsProcessor extends DefaultProcessor { 49 async insertByHighAuthority(rdbStore: data_rdb.RdbStore, uri: string, values: data_rdb.ValuesBucket, callback: Function) { 50 const callerName = getBundleNameByUri(uri); 51 initValueCreator(values, callerName); 52 const isCalendarExist = await isCalendarContainSameId(rdbStore, values); 53 if (isCalendarExist) { 54 this.insertEventWithInstanceExpand(rdbStore, uri, values, callback); 55 } else { 56 Log.warn(TAG, 'not support insert operation'); 57 const err: BusinessError = { 58 code: ErrorCode.UN_SUPPORT_OPERATION, 59 name: 'UnSupportedOperationException', 60 message: 'The calling application cannot insert an event without its own calendar' 61 }; 62 callback(err, -1); 63 } 64 } 65 66 async insertByLowAuthority(rdbStore: data_rdb.RdbStore, uri: string, values: data_rdb.ValuesBucket, callback: Function) { 67 const callerName = getBundleNameByUri(uri); 68 initValueCreator(values, callerName); 69 const isCalendarCreatorExist = await isCalendarContainSameCreator(rdbStore, values); 70 if (isCalendarCreatorExist) { 71 this.insertEventWithInstanceExpand(rdbStore, uri, values, callback); 72 } else { 73 Log.warn(TAG, 'not support insert operation'); 74 const err: BusinessError = { 75 code: ErrorCode.UN_SUPPORT_OPERATION, 76 name: 'UnSupportedOperationException', 77 message: 'The calling application cannot insert an event with different creator from calendar' 78 }; 79 callback(err, -1); 80 } 81 } 82 83 async deleteByLowAuthority(rdbStore: data_rdb.RdbStore, uri: string, predicates: dataSharePredicates.DataSharePredicates, callback: Function) { 84 const callerName = getBundleNameByUri(uri); 85 initPredicateCreator(predicates, callerName); 86 this.doDelete(rdbStore, uri, predicates, callback); 87 } 88 89 async updateByHighAuthority(rdbStore: data_rdb.RdbStore, uri: string, values: data_rdb.ValuesBucket, predicates: dataSharePredicates.DataSharePredicates, callback: Function) { 90 deleteValueCreator(values); 91 this.updateEventWithInstance(rdbStore, uri, values, predicates, callback); 92 } 93 94 async updateByLowAuthority(rdbStore: data_rdb.RdbStore, uri: string, values: data_rdb.ValuesBucket, predicates: dataSharePredicates.DataSharePredicates, callback: Function) { 95 const callerName = getBundleNameByUri(uri); 96 deleteValueCreator(values); 97 initPredicateCreator(predicates, callerName); 98 this.updateEventWithInstance(rdbStore, uri, values, predicates, callback); 99 } 100 101 async queryByLowAuthority(rdbStore: data_rdb.RdbStore, uri: string, columns: Array<string>, predicates: dataSharePredicates.DataSharePredicates, callback: Function) { 102 const callerName = getBundleNameByUri(uri); 103 initPredicateCreator(predicates, callerName); 104 this.doQuery(rdbStore, uri, columns, predicates, callback); 105 } 106 107 /** 108 * 插入 Event 并扩展该 Event 的实例 Instance 109 * 110 * @param rdbStore rdb数据库 111 * @param uri DataShare的uri 112 * @param values 插入的数据 113 * @param callback 回调方法 114 */ 115 async insertEventWithInstanceExpand(rdbStore: data_rdb.RdbStore, uri: string, values: data_rdb.ValuesBucket, callback: Function) { 116 this.doInsert(rdbStore, uri, values, (err: BusinessError, rowId: number) => { 117 Log.debug(TAG, `before insert callback`); 118 if (hasNoError(err)) { 119 acquireExpandOne(rdbStore, rowId, values); 120 } 121 callback(err, rowId); 122 Log.debug(TAG, `after insert callback`); 123 }); 124 } 125 126 /** 127 * 更新 Event,并同步更新 Instance 128 * 129 * @param rdbStore rdb数据库 130 * @param uri DataShare的uri 131 * @param values 更新的数据 132 * @param predicates 更新条件 133 * @param callback 回调方法 134 */ 135 async updateEventWithInstance(rdbStore: data_rdb.RdbStore, uri: string, values: data_rdb.ValuesBucket, predicates: dataSharePredicates.DataSharePredicates, callback: Function) { 136 let needUpdatedEventIds: Array<number>; 137 if (isNeedRefreshInstances(values)) { 138 needUpdatedEventIds = await queryEventIdsByPredicate(rdbStore, predicates); 139 } 140 this.doUpdate(rdbStore, uri, values, predicates, (err: BusinessError, count: Function) => { 141 Log.debug(TAG, `before update callback`); 142 if (hasNoError(err)) { 143 updateInstances(rdbStore, needUpdatedEventIds); 144 } 145 callback(err, count); 146 Log.debug(TAG, `after update callback`); 147 }) 148 } 149} 150 151/** 152 * 检查待插入的 event 与 calendar 表中相同 calendar_id 的元组是否拥有相同的 creator 153 * 154 * @param rdbStore rdb数据库 155 * @param values 插入操作的数据 156 * @return true 相同 false 不相同 157 */ 158async function isCalendarContainSameCreator(rdbStore: data_rdb.RdbStore, values: data_rdb.ValuesBucket): Promise<boolean> { 159 Log.debug(TAG, 'isCalendarContainSameCreator start'); 160 const EventCreator = values[EventColumns.CREATOR]; 161 let resultSet = await queryCalendarIdAndCreatorByEvent(rdbStore, values); 162 if (resultSet === null || resultSet === undefined) { 163 return false; 164 } 165 const calendarsIndexes: CalendarsIndexes | undefined = parseCalendarsIndexes(resultSet); 166 if (resultSet.goToFirstRow()) { 167 let calendars: Calendars | undefined = parseCalendars(resultSet, calendarsIndexes); 168 if (calendars === null || calendars === undefined) { 169 return false; 170 } 171 if (calendars.creator === EventCreator || calendars.creator === APP_NAME.CALENDARDATA) { 172 return true; 173 } 174 } 175 return false; 176} 177 178/** 179 * 检查待插入的 event 与 calendar 表中是否存在相同 calendar_id 的元组 180 * 181 * @param rdbStore rdb数据库 182 * @param values 插入操作的数据 183 * @return true 相同 false 不相同 184 */ 185async function isCalendarContainSameId(rdbStore: data_rdb.RdbStore, values: data_rdb.ValuesBucket): Promise<boolean> { 186 Log.debug(TAG, 'isCalendarContainSameId start'); 187 let resultSet = await queryCalendarIdAndCreatorByEvent(rdbStore, values); 188 if (resultSet === null || resultSet === undefined) { 189 return false; 190 } 191 if (resultSet.rowCount > 0) { 192 return true; 193 } 194 return false; 195} 196 197/** 198 * 查询待插入的 event 数据中 calendar_id 与 calendar 表相同的结果 199 * 200 * @param rdbStore rdb数据库 201 * @param values 插入操作的数据 202 * @return DataShareResultSet 203 */ 204async function queryCalendarIdAndCreatorByEvent(rdbStore: data_rdb.RdbStore, values: data_rdb.ValuesBucket): Promise<data_rdb.ResultSet> { 205 const calendarId = values[EventColumns.CALENDAR_ID] as ValueType; 206 const columns = [CalendarsColumns.ID, CalendarsColumns.CREATOR]; 207 let predicates = new dataSharePredicates.DataSharePredicates(); 208 predicates.equalTo(CalendarsColumns.ID, calendarId); 209 let resultSet: data_rdb.ResultSet = {} as data_rdb.ResultSet; 210 try { 211 resultSet = await rdbStore.query(CalendarsColumns.TABLE_NAME, predicates, columns); 212 } catch (err) { 213 Log.error(TAG, 'Calendars query data error'); 214 } 215 return resultSet; 216} 217 218/** 219 * 根据Predicate查出待刷新的Events ID列表,用于后续刷新Instances的依据 220 * 221 * @param rdbStore rdb数据库 222 * @param predicates update条件,用于定位需要刷新Instances对应eventId的范围 223 */ 224async function queryEventIdsByPredicate(rdbStore: data_rdb.RdbStore, predicates: dataSharePredicates.DataSharePredicates): Promise<Array<number>> { 225 const resultArray: Array<number> = new Array(); 226 const columns = [EventColumns.ID]; 227 try { 228 const resultSet = await rdbStore.query(EventColumns.TABLE_NAME, predicates, columns); 229 if (resultSet === null || resultSet === undefined) { 230 Log.error(TAG, 'queryEventIdsByPredicate get invalid resultSet'); 231 return resultArray; 232 } 233 if (resultSet.rowCount === 0 || !resultSet.goToFirstRow()) { 234 Log.info(TAG, `queryEventIdsByPredicate row count:${resultSet?.rowCount}`); 235 return resultArray; 236 } 237 do { 238 const eventId = resultSet.getLong(resultSet.getColumnIndex(EventColumns.ID)); 239 resultArray.push(eventId); 240 } while (resultSet.goToNextRow()); 241 } catch (err) { 242 Log.error(TAG, `queryEventIdsByPredicate get err: ${err?.message}`); 243 } 244 return resultArray; 245} 246 247/** 248 * 批量刷新Instances 249 * 250 * @param rdbStore rdb数据库 251 * @param updatedIds 待刷新的eventId列表 252 */ 253async function updateInstances(rdbStore: data_rdb.RdbStore, updatedIds: Array<number>) { 254 if (updatedIds === null || updatedIds === undefined || updatedIds.length === 0) { 255 return; 256 } 257 258 // 1.先批量查询出全部Events数据 259 const eventsMap: Map<number, Events> = await queryEventsByIds(rdbStore, updatedIds); 260 261 if (eventsMap === null || eventsMap === undefined || eventsMap.size === 0) { 262 Log.warn(TAG, 'updateInstances with invalid eventsMap'); 263 return; 264 } 265 266 // 2.再遍历生成Instances 267 for (let eventId of updatedIds) { 268 // 基于eventId单条刷新Instances,需传入events字段值数据 269 acquireUpdateOne(rdbStore, eventId, eventsMap.get(eventId)); 270 } 271} 272 273/** 274 * 根据EventIds查询出Events数据,用于生成Instances,先批量查询避免在for循环中查询 275 * 276 * @param rdbStore rdb数据库 277 * @param eventIds 需查询的eventIds集合 278 * @return Map<number, Events> eventId-Events的map 279 */ 280async function queryEventsByIds(rdbStore: data_rdb.RdbStore, eventIds: Array<number>): Promise<Map<number, Events>> { 281 const resultMap: Map<number, Events> = new Map(); 282 const predicate = new dataSharePredicates.DataSharePredicates(); 283 predicate.in(EventColumns.ID, eventIds); 284 const columns = UPDATE_INSTANCES_COLUMNS; 285 columns.push(EventColumns.ID); 286 columns.push(EventColumns.CREATOR); 287 try { 288 const resultSet = await rdbStore.query(EventColumns.TABLE_NAME, predicate, columns); 289 if (resultSet === null || resultSet === undefined) { 290 Log.error(TAG, 'queryEventsByIds get invalid resultSet'); 291 return resultMap; 292 } 293 if (!resultSet.goToFirstRow()) { 294 Log.error(TAG, `queryEventsByIds goto first row failed ${resultSet?.rowCount}`); 295 return resultMap; 296 } 297 const indexes: EventIndexes | undefined = parseIndexes(resultSet); 298 do { 299 const event: Events | undefined = parseEvents(resultSet, indexes); 300 if (event != undefined) { 301 resultMap.set(event.id, event); 302 } 303 } while (resultSet.goToNextRow()); 304 } catch (err) { 305 Log.error(TAG, `queryEventsByIds get err ${err?.message}`); 306 } 307 return resultMap; 308}