• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/**
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import ConfigData from '../../../../../../utils/src/main/ets/default/baseUtil/ConfigData';
17import Log from '../../../../../../utils/src/main/ets/default/baseUtil/LogDecorator';
18import { BaseData } from '../../../../../../utils/src/main/ets/default/bean/BaseData';
19import LogUtil from '../../../../../../utils/src/main/ets/default/baseUtil/LogUtil';
20import { GlobalContext } from '../../../../../../utils/src/main/ets/default/baseUtil/GlobalContext';
21import SearchConfig from '../common/SearchConfig';
22import SearchData from '../model/SearchData';
23import SearchDataProvider from '../provider/SearchDataProvider';
24import BaseParseConfModel from '../../../../../../utils/src/main/ets/default/model/BaseParseConfModel';
25import ohosDataRdb from '@ohos.data.rdb';
26import featureAbility from '@ohos.ability.featureAbility';
27
28/**
29 * Search service class
30 */
31export default class SearchModel {
32  private rdbStore;
33  private searchDataConfig;
34
35  constructor(configData: Array<Object>) {
36    this.searchDataConfig = configData;
37  }
38
39  /**
40   * Initialize search data
41   */
42  @Log
43  public async initSearchData(): Promise<void> {
44    const searchData = await this.gatherSearchData();
45    await this.initRdbSearchData(searchData);
46  }
47
48  /**
49   * Search
50   *
51   * @param query - query content
52   */
53  @Log
54  public async search(query: string): Promise<SearchData[]> {
55    if (!query) {
56      return []
57    }
58    query = this.sqlLikeCharReplace(query);
59    await this.initRdb();
60
61    // query search data
62    let predicates = new ohosDataRdb.RdbPredicates(SearchConfig.search.TABLE_NAME);
63    predicates.like(SearchConfig.search.FIELD_KEYWORD, `%${query}%`)
64      .or().like(SearchConfig.search.FIELD_SUMMARY, `%${query}%`)
65      .or().like(SearchConfig.search.FIELD_SYNONYM, `%${query}%`)
66      .orderByAsc(SearchConfig.search.FIELD_URI);
67
68    let resultSet = await this.rdbStore.query(predicates, [
69    SearchConfig.search.FIELD_ICON,
70    SearchConfig.search.FIELD_TITLE,
71    SearchConfig.search.FIELD_KEYWORD,
72    SearchConfig.search.FIELD_SUMMARY,
73    SearchConfig.search.FIELD_URI
74    ]);
75
76    // build search data from resultSet
77    let searchData: SearchData[] = [];
78    while (resultSet.goToNextRow()) {
79      const data = new SearchData();
80      data.icon = resultSet.getString(0);
81      data.title = resultSet.getString(1);
82      data.keyword = resultSet.getString(2);
83      data.summary = resultSet.getString(3);
84      data.uri = resultSet.getString(4);
85      searchData.push(data);
86    }
87    resultSet.close();
88    resultSet = null;
89
90    return searchData;
91  }
92
93  /**
94   * Initialize rdb
95   */
96  @Log
97  private async initRdb(): Promise<void> {
98    LogUtil.log('settings initRdb.');
99
100    if (!this.rdbStore) {
101      LogUtil.log('settings RDB has not been initialized yet.');
102
103      // database init
104      const STORE_CONFIG = {
105        name: SearchConfig.RDB_NAME
106      };
107      let context = GlobalContext.getContext().getObject(GlobalContext.globalKeySettingsAbilityContext) as Context;
108      this.rdbStore = await ohosDataRdb.getRdbStore(context, STORE_CONFIG, 1);
109      LogUtil.log('settings SettingsSearch.db is ready.');
110
111      // table SEARCH_DATA init
112      await this.rdbStore.executeSql(SearchConfig.search.DDL_TABLE_CREATE, null);
113      LogUtil.log('settings table SEARCH_DATA is ready.');
114    }
115  }
116
117  /**
118   * Handle special characters for sql.like
119   *
120   * @param query - query content
121   */
122  @Log
123  private sqlLikeCharReplace(query: string): string {
124    query = query.replace("[", "/[");
125    query = query.replace("]", "/]");
126    query = query.replace("/", "//");
127    query = query.replace("%", "/%");
128    query = query.replace("&", "/&");
129    query = query.replace("'", "''");
130    query = query.replace("(", "/(");
131    query = query.replace(")", "/)");
132    query = query.replace("_", "/_");
133    return query;
134  }
135
136  /**
137   * Gather search data from providers
138   *
139   * @param searchData - search data to be grouped
140   */
141  @Log
142  private async gatherSearchData(): Promise<SearchData[]> {
143    // init uriConfigMapping
144    const uriConfigMapping = new Map();
145    this.searchDataConfig.forEach(config => {
146      uriConfigMapping.set(config.settingUri, config);
147    })
148
149    // get searchData (note: settingList must be the first)
150    let searchData: SearchData[] = await this.getSearchData(this.searchDataConfig[0].settingUri, '', uriConfigMapping);
151    LogUtil.log('settings search searchData: ' + JSON.stringify(searchData));
152
153    return searchData;
154  }
155
156  /**
157   * Initialize rdb search data
158   *
159   * @param searchData - search data
160   */
161  @Log
162  private async initRdbSearchData(searchData: SearchData[]): Promise<void> {
163    LogUtil.log('settings search old data if exists.');
164    await this.initRdb();
165
166    // delete old data if exists
167    await this.rdbStore.executeSql(SearchConfig.search.SQL_DELETE_ALL, null);
168    LogUtil.log('settings search old data if exists.');
169
170    // insert new data into table
171    for (let data of searchData) {
172      const valueBucket = {};
173      valueBucket[SearchConfig.search.FIELD_URI] = data.uri;
174      valueBucket[SearchConfig.search.FIELD_ICON] = data.icon;
175      valueBucket[SearchConfig.search.FIELD_TITLE] = data.title;
176      valueBucket[SearchConfig.search.FIELD_KEYWORD] = data.keyword;
177      valueBucket[SearchConfig.search.FIELD_SUMMARY] = data.summary;
178      valueBucket[SearchConfig.search.FIELD_SYNONYM] = data.synonym;
179      let ret = await this.rdbStore.insert(SearchConfig.search.TABLE_NAME, valueBucket)
180      LogUtil.log("settings: search insert data: " + ret)
181    }
182  }
183
184  /**
185   * Get search data
186   *
187   * @param settingUri - setting uri
188   * @param settingIcon - setting icon
189   * @param uriConfigMapping - uri config mapping
190   */
191  @Log
192  private async getSearchData(settingUri: string, settingIcon: string, uriConfigMapping: Map<string, any>): Promise<SearchData[]> {
193    if (!uriConfigMapping.get(settingUri)) {
194      return [];
195    }
196
197    // get search data from provider
198    const provider: SearchDataProvider = uriConfigMapping.get(settingUri).provider;
199    let searchProviderData: SearchData[] = await provider.getSearchData();
200
201    // set uri, icon
202    searchProviderData.forEach(providerData => {
203      if (!providerData.uri) {
204        providerData.uri = settingUri;
205      }
206      providerData.icon = settingIcon;
207    });
208
209    // get setting list
210    let settingConfig = ConfigData.FILE_URI.concat(uriConfigMapping.get(settingUri).settingRawJson)
211    let settingList: BaseData[] = this.getSettingList(settingConfig);
212
213    // get child page search
214    for (const setting of settingList) {
215      const icon = settingIcon ? settingIcon : setting.settingIcon; // higher priority for parent icon
216      const childData = await this.getSearchData(setting.settingUri, icon, uriConfigMapping);
217      searchProviderData = searchProviderData.concat(childData);
218    }
219    ;
220
221    return searchProviderData;
222  }
223
224  /**
225   * Get setting list which includes settingUri in each setting
226   *
227   * @param settingConfig - setting config path
228   */
229  @Log
230  private getSettingList(settingConfig: string): BaseData[] {
231    let result = [];
232
233    let settingList: any[] = BaseParseConfModel.getJsonData(settingConfig);
234    settingList.forEach(setting => {
235      if (setting.settingUri) {
236        let baseData = new BaseData();
237        baseData.settingIcon = setting.settingIcon;
238        baseData.settingUri = setting.settingUri;
239        result.push(baseData);
240      }
241    });
242
243    return result;
244  }
245}
246