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