• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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}