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 { Log } from '@ohos/common/src/main/ets/utils/Log';
20import { getBundleNameByUri } from '@ohos/common/src/main/ets/utils/UrlUtils';
21import { EventColumns } from '@ohos/datastructure/src/main/ets/events/EventColumns';
22import { Events } from '@ohos/datastructure/src/main/ets/events/Events';
23import { RemindersColumns } from '@ohos/datastructure/src/main/ets/reminders/RemindersColumns';
24import { parseIndexes, EventIndexes } from '@ohos/datastructure/src/main/ets/events/EventIndexes';
25import { parseEvents } from '@ohos/datastructure/src/main/ets/events/EventParser';
26import { initValueCreator, initPredicateCreator, deleteValueCreator } from '../DatabaseProcessorHelper';
27import { DefaultProcessor } from '../DefaultProcessor';
28import { ErrorCode } from '../../constants/ErrorCode';
29import { BusinessError } from '@ohos.base';
30import { ValueType } from '@ohos.data.ValuesBucket';
31
32const TAG = 'RemindersProcessor';
33
34/**
35 * the RemindersProcessor table processor
36 *
37 * @since 2022-10-17
38 */
39export class RemindersProcessor extends DefaultProcessor {
40  public constructor(isFromMigrate?: boolean) {
41    super(isFromMigrate);
42  }
43
44  async insertByHighAuthority(rdbStore: data_rdb.RdbStore, uri: string,
45                              values: data_rdb.ValuesBucket, callback: Function) {
46    if (!this.isFromMigrate) {
47      const callerName = getBundleNameByUri(uri);
48      initValueCreator(values, callerName);
49    }
50    const isEventExist = await isEventSameWithReminderId(rdbStore, values);
51    if (isEventExist) {
52      this.doInsert(rdbStore, uri, values, callback);
53    } else {
54      Log.warn(TAG, 'not support insert operation');
55      const err: BusinessError = {
56        code: ErrorCode.UN_SUPPORT_OPERATION,
57        name: 'UnSupportedOperationException',
58        message: 'The calling application cannot insert an reminder without its own event'
59      };
60      callback(err, -1);
61    }
62  }
63
64  async insertByLowAuthority(rdbStore: data_rdb.RdbStore, uri: string,
65                             values: data_rdb.ValuesBucket, callback: Function) {
66    if (!this.isFromMigrate) {
67      const callerName = getBundleNameByUri(uri);
68      initValueCreator(values, callerName);
69    }
70    const isEventCreatorExist = await isEventSameWithReminderCreator(rdbStore, values);
71    if (isEventCreatorExist) {
72      this.doInsert(rdbStore, uri, values, callback);
73    } else {
74      Log.warn(TAG, 'not support insert operation');
75      const err: BusinessError = {
76        code: ErrorCode.UN_SUPPORT_OPERATION,
77        name: 'UnSupportedOperationException',
78        message: 'The calling application cannot insert an reminder with different creator from event'
79      };
80      callback(err, -1);
81    }
82  }
83
84  async deleteByLowAuthority(rdbStore: data_rdb.RdbStore, uri: string,
85                             predicates: dataSharePredicates.DataSharePredicates, callback: Function) {
86    const callerName = getBundleNameByUri(uri);
87    initPredicateCreator(predicates, callerName);
88    this.doDelete(rdbStore, uri, predicates, callback);
89  }
90
91  async updateByHighAuthority(rdbStore: data_rdb.RdbStore, uri: string, values: data_rdb.ValuesBucket,
92                              predicates: dataSharePredicates.DataSharePredicates, callback: Function) {
93    values = deleteValueCreator(values);
94    this.doUpdate(rdbStore, uri, values, predicates, callback)
95  }
96
97  async updateByLowAuthority(rdbStore: data_rdb.RdbStore, uri: string, values: data_rdb.ValuesBucket,
98                             predicates: dataSharePredicates.DataSharePredicates, callback: Function) {
99    const callerName = getBundleNameByUri(uri);
100    values = deleteValueCreator(values);
101    initPredicateCreator(predicates, callerName);
102    this.doUpdate(rdbStore, uri, values, predicates, callback)
103  }
104
105  async queryByLowAuthority(rdbStore: data_rdb.RdbStore, uri: string, columns: Array<string>,
106                            predicates: dataSharePredicates.DataSharePredicates, callback: Function) {
107    const callerName = getBundleNameByUri(uri);
108    initPredicateCreator(predicates, callerName);
109    this.doQuery(rdbStore, uri, columns, predicates, callback);
110  }
111}
112/**
113 * 检查待插入的 reminder 与 event 表中相同 event_id 的元组是否拥有相同的 creator
114 * @param rdbStore rdb数据库
115 * @param values 插入操作的数据
116 * @return true 相同 false 不相同
117 */
118async function isEventSameWithReminderCreator(rdbStore: data_rdb.RdbStore,
119                                              values: data_rdb.ValuesBucket): Promise<boolean> {
120  Log.debug(TAG, 'isEventSameWithReminderCreator start');
121  const reminderCreator = values[RemindersColumns.CREATOR];
122  let resultSet = await queryEventIdAndCreatorByReminder(rdbStore, values);
123  if (resultSet === null || resultSet === undefined) {
124    return false;
125  }
126  try {
127    const eventIndexes: EventIndexes = parseIndexes(resultSet) as EventIndexes;
128    if (resultSet.goToFirstRow()) {
129      let events: Events | undefined = parseEvents(resultSet, eventIndexes);
130      if (events === null || events === undefined) {
131        return false;
132      }
133      if (events.creator === reminderCreator) {
134        return true;
135      }
136    }
137  } catch (err) {
138    Log.warn(TAG, `isEventSameWithReminderCreator err ${JSON.stringify(err)}`);
139  } finally {
140    if (resultSet) {
141      resultSet.close();
142    }
143  }
144  return false;
145}
146
147/**
148 * 检查待插入的 reminder 与 event 表中是否存在相同 event_id 的元组
149 * @param rdbStore rdb数据库
150 * @param values 插入操作的数据
151 * @return true 相同 false 不相同
152 */
153async function isEventSameWithReminderId(rdbStore: data_rdb.RdbStore,
154                                         values: data_rdb.ValuesBucket): Promise<boolean> {
155  Log.debug(TAG, 'isEventSameWithReminderId start');
156  let resultSet = await queryEventIdAndCreatorByReminder(rdbStore, values);
157  try {
158    if (resultSet === null || resultSet === undefined) {
159      return false;
160    }
161    if (resultSet.rowCount > 0) {
162      return true;
163    }
164  } catch (err) {
165    Log.warn(TAG, `isEventSameWithReminderId err ${JSON.stringify(err)}`);
166  } finally {
167    if (resultSet) {
168      resultSet.close();
169    }
170  }
171  return false;
172}
173
174/**
175 * 查询待插入的 reminder 数据中 event_id 与 event 表相同的结果
176 * @param rdbStore rdb数据库
177 * @param values 插入操作的数据
178 * @return DataShareResultSet
179 */
180async function queryEventIdAndCreatorByReminder(rdbStore: data_rdb.RdbStore,
181                                                values: data_rdb.ValuesBucket): Promise<data_rdb.ResultSet> {
182  const eventId = values[RemindersColumns.EVENT_ID] as ValueType;
183  const columns = [EventColumns.ID, EventColumns.CREATOR];
184  let predicates = new dataSharePredicates.DataSharePredicates();
185  predicates.equalTo(EventColumns.ID, eventId);
186  let resultSet: data_rdb.ResultSet = {} as data_rdb.ResultSet;
187  try {
188    resultSet = await rdbStore.query(EventColumns.TABLE_NAME, predicates, columns);
189  } catch (err) {
190    Log.error(TAG, 'Event query data error');
191  }
192  return resultSet;
193}