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