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