• 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 = null;
69    try {
70      resultSet = await this.rdbStore.query(predicates, [
71        SearchConfig.search.FIELD_ICON,
72        SearchConfig.search.FIELD_TITLE,
73        SearchConfig.search.FIELD_KEYWORD,
74        SearchConfig.search.FIELD_SUMMARY,
75        SearchConfig.search.FIELD_URI
76      ]);
77      LogUtil.log("settings: query data: " + resultSet);
78    } catch(err) {
79      LogUtil.error('query data err.' + err.message);
80      return [];
81    }
82    // build search data from resultSet
83    let searchData: SearchData[] = [];
84    while (resultSet.goToNextRow()) {
85      const data = new SearchData();
86      data.icon = resultSet.getString(0);
87      data.title = resultSet.getString(1);
88      data.keyword = resultSet.getString(2);
89      data.summary = resultSet.getString(3);
90      data.uri = resultSet.getString(4);
91      searchData.push(data);
92    }
93    resultSet.close();
94    resultSet = null;
95
96    return searchData;
97  }
98
99  /**
100   * Initialize rdb
101   */
102  @Log
103  private async initRdb(): Promise<void> {
104    LogUtil.log('settings initRdb.');
105
106    if (!this.rdbStore) {
107      LogUtil.log('settings RDB has not been initialized yet.');
108
109      // database init
110      const STORE_CONFIG = {
111        name: SearchConfig.RDB_NAME
112      };
113      let context = GlobalContext.getContext().getObject(GlobalContext.globalKeySettingsAbilityContext) as Context;
114      this.rdbStore = await ohosDataRdb.getRdbStore(context, STORE_CONFIG, 1);
115      LogUtil.log('settings SettingsSearch.db is ready.');
116
117      // table SEARCH_DATA init
118      try {
119        await this.rdbStore.executeSql(SearchConfig.search.DDL_TABLE_CREATE, null);
120      } catch(err) {
121        LogUtil.error(`settings: executeSql err ${err.message}`);
122      }
123      LogUtil.log('settings table SEARCH_DATA is ready.');
124    }
125  }
126
127  /**
128   * Handle special characters for sql.like
129   *
130   * @param query - query content
131   */
132  @Log
133  private sqlLikeCharReplace(query: string): string {
134    query = query.replace("[", "/[");
135    query = query.replace("]", "/]");
136    query = query.replace("/", "//");
137    query = query.replace("%", "/%");
138    query = query.replace("&", "/&");
139    query = query.replace("'", "''");
140    query = query.replace("(", "/(");
141    query = query.replace(")", "/)");
142    query = query.replace("_", "/_");
143    return query;
144  }
145
146  /**
147   * Gather search data from providers
148   *
149   * @param searchData - search data to be grouped
150   */
151  @Log
152  private async gatherSearchData(): Promise<SearchData[]> {
153    // init uriConfigMapping
154    const uriConfigMapping = new Map();
155    this.searchDataConfig.forEach(config => {
156      uriConfigMapping.set(config.settingUri, config);
157    })
158
159    // get searchData (note: settingList must be the first)
160    let searchData: SearchData[] = await this.getSearchData(this.searchDataConfig[0].settingUri, '', uriConfigMapping);
161    LogUtil.log('settings search searchData: ' + JSON.stringify(searchData));
162
163    return searchData;
164  }
165
166  /**
167   * Initialize rdb search data
168   *
169   * @param searchData - search data
170   */
171  @Log
172  private async initRdbSearchData(searchData: SearchData[]): Promise<void> {
173    LogUtil.log('settings search old data if exists.');
174    await this.initRdb();
175
176    // delete old data if exists
177    try {
178      await this.rdbStore.executeSql(SearchConfig.search.SQL_DELETE_ALL, null);
179    } catch(err) {
180      LogUtil.error("settings: executeSql DELETE err " + err.message);
181    }
182    LogUtil.log('settings search old data if exists.');
183
184    // insert new data into table
185    for (let data of searchData) {
186      const valueBucket = {};
187      valueBucket[SearchConfig.search.FIELD_URI] = data.uri;
188      valueBucket[SearchConfig.search.FIELD_ICON] = data.icon;
189      valueBucket[SearchConfig.search.FIELD_TITLE] = data.title;
190      valueBucket[SearchConfig.search.FIELD_KEYWORD] = data.keyword;
191      valueBucket[SearchConfig.search.FIELD_SUMMARY] = data.summary;
192      valueBucket[SearchConfig.search.FIELD_SYNONYM] = data.synonym;
193      try {
194        let ret = await this.rdbStore.insert(SearchConfig.search.TABLE_NAME, valueBucket);
195        LogUtil.log("settings: search insert data: " + ret);
196      } catch(err) {
197        LogUtil.error('insert data err ' + err.message);
198      }
199    }
200  }
201
202  /**
203   * Get search data
204   *
205   * @param settingUri - setting uri
206   * @param settingIcon - setting icon
207   * @param uriConfigMapping - uri config mapping
208   */
209  @Log
210  private async getSearchData(settingUri: string, settingIcon: string, uriConfigMapping: Map<string, any>): Promise<SearchData[]> {
211    if (!uriConfigMapping.get(settingUri)) {
212      return [];
213    }
214
215    // get search data from provider
216    const provider: SearchDataProvider = uriConfigMapping.get(settingUri).provider;
217    let searchProviderData: SearchData[] = await provider.getSearchData();
218
219    // set uri, icon
220    searchProviderData.forEach(providerData => {
221      if (!providerData.uri) {
222        providerData.uri = settingUri;
223      }
224      providerData.icon = settingIcon;
225    });
226
227    // get setting list
228    let settingConfig = ConfigData.FILE_URI.concat(uriConfigMapping.get(settingUri).settingRawJson)
229    let settingList: BaseData[] = this.getSettingList(settingConfig);
230
231    // get child page search
232    for (const setting of settingList) {
233      const icon = settingIcon ? settingIcon : setting.settingIcon; // higher priority for parent icon
234      const childData = await this.getSearchData(setting.settingUri, icon, uriConfigMapping);
235      searchProviderData = searchProviderData.concat(childData);
236    }
237    ;
238
239    return searchProviderData;
240  }
241
242  /**
243   * Get setting list which includes settingUri in each setting
244   *
245   * @param settingConfig - setting config path
246   */
247  @Log
248  private getSettingList(settingConfig: string): BaseData[] {
249    let result = [];
250
251    let settingList: any[] = BaseParseConfModel.getJsonData(settingConfig);
252    settingList.forEach(setting => {
253      if (setting.settingUri) {
254        let baseData = new BaseData();
255        baseData.settingIcon = setting.settingIcon;
256        baseData.settingUri = setting.settingUri;
257        result.push(baseData);
258      }
259    });
260
261    return result;
262  }
263}
264