• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 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 data_rdb from '@ohos.data.relationalStore'
17import common from '@ohos.app.ability.common'
18import Contact from '../model/Contact'
19import Logger from '../model/Logger'
20import { STORE_CONFIG, TABLE_NAME, TYPE_INSERT, TYPE_UPDATE, TYPE_DELETE } from '../model/RdbConst'
21import { ValuesBucket } from '@ohos.data.ValuesBucket';
22
23const TAG = 'RdbModel'
24
25export default class RdbModel {
26  private rdbStore: data_rdb.RdbStore | undefined = undefined
27  private tableName: string = ''
28  private sqlCreateTable: string = ''
29  private columns: Array<string> = []
30  private distributedTable: string = ''
31  private dataChangeCallback: Function | null = null
32  private dataChangeDetailCallback: Function | null = null
33  private isCreateDbDone: boolean = false
34  private context: common.UIAbilityContext
35
36  constructor(tableName: string, sqlCreateTable: string, columns: Array<string>, context: common.UIAbilityContext) {
37    this.tableName = tableName
38    this.sqlCreateTable = sqlCreateTable
39    this.columns = columns
40    this.context = context
41
42    this.getRdbStore()
43  }
44
45  // 初始化数据库
46  async getRdbStore() {
47    Logger.info(TAG, 'getRdbStore begin')
48    if (this.isCreateDbDone) {
49      Logger.info(TAG, 'getRdbStore isCreateDbDone')
50      return
51    }
52    try {
53      // 获取数据库存储对象
54      this.rdbStore = await data_rdb.getRdbStore(this.context, STORE_CONFIG);
55    } catch (err) {
56      console.info(`getRdbStore err ${JSON.stringify(err)}`);
57    }
58    Logger.info(TAG, 'getRdbStore end')
59    try {
60      // 执行sql语句,联系人个各个属性设定
61      if (this.rdbStore != undefined) {
62        await this.rdbStore.executeSql(this.sqlCreateTable)
63        console.info(`create tabe start ` + this.sqlCreateTable);
64        // 设置分布式表,表明为contact
65        await this.rdbStore.setDistributedTables([this.tableName])
66      }
67    } catch (e) {
68      Logger.error(TAG, 'getRdbStore:' + JSON.stringify(e))
69    }
70    // 分布式数据库创建为完成
71    this.isCreateDbDone = true
72    Logger.info(TAG, 'create table done')
73  }
74
75  async insertData(contact: Contact) {
76    let value1 = contact.name;
77    let value2 = contact.gender;
78    let value3 = contact.phone;
79    let value4 = contact.remark;
80    let value5 = contact.age;
81
82    const valueBucket: ValuesBucket = {
83      'name': value1,
84      'gender': value2,
85      'phone': value3,
86      'remark': value4,
87      'age': value5,
88    }
89    if (this.rdbStore != undefined) {
90      let ret = await this.rdbStore.insert(this.tableName, valueBucket, data_rdb.ConflictResolution.ON_CONFLICT_REPLACE)
91      Logger.info(TAG, `insert done:${ret}`)
92    }
93  }
94
95  async updateData(contact: Contact) {
96    let value1 = contact.name;
97    let value2 = contact.gender;
98    let value3 = contact.phone;
99    let value4 = contact.remark;
100    let value5 = contact.age;
101
102    const valueBucket: ValuesBucket = {
103      'name': value1,
104      'gender': value2,
105      'phone': value3,
106      'remark': value4,
107      'age': value5,
108    }
109    let predicates = new data_rdb.RdbPredicates(this.tableName)
110    Logger.info(TAG, `updateData id=${contact.id}`)
111    predicates.equalTo('id', contact.id)
112    if (this.rdbStore != undefined) {
113      let ret = await this.rdbStore.update(valueBucket, predicates)
114      Logger.info(TAG, `updated row count: ${ret}`)
115    }
116  }
117
118  async deleteContacts(contacts: Array<Contact>) {
119    let predicates = new data_rdb.RdbPredicates(this.tableName)
120    contacts.forEach((contact) => {
121      predicates.or()
122        .equalTo('id', contact.id)
123    })
124    if (this.rdbStore != undefined) {
125      let rows = await this.rdbStore.delete(predicates)
126      Logger.info(TAG, `delete rows: ${rows}`)
127    }
128  }
129
130  async query(predicates: data_rdb.RdbPredicates): Promise<Array<Contact>> {
131    Logger.info(TAG, 'query start')
132    Logger.info(TAG, 'predicates is ' + JSON.stringify(predicates))
133    Logger.info(TAG, 'columns ' + JSON.stringify(this.columns))
134
135    if (this.rdbStore != undefined) {
136      // 默认查询所有列
137      let resultSet: data_rdb.ResultSet = await this.rdbStore.query(predicates, this.columns);
138      Logger.info(TAG, 'result is ' + JSON.stringify(resultSet.rowCount))
139      // 处理查询到的结果数组
140      return this.getListFromResultSet(resultSet)
141    }
142    return []
143  }
144
145  async syncData(predicates: data_rdb.RdbPredicates) {
146    Logger.info(TAG, 'syncData')
147    if (this.rdbStore != undefined) {
148      let result = await this.rdbStore.sync(data_rdb.SyncMode.SYNC_MODE_PUSH, predicates)
149      for (let i = 0; i < result.length; i++) {
150        Logger.info(TAG, `device=${result[i][0]}, status = ${result[i][1]}`)
151      }
152    }
153  }
154
155  async onDataChange(device: string, callback: Function) {
156    Logger.info(TAG, `onDataChange enter,device=` + device + ` ,tableName = ` + this.tableName)
157    try {
158      if (this.rdbStore != undefined) {
159        this.distributedTable = await this.rdbStore.obtainDistributedTableName(device, this.tableName)
160        Logger.info(TAG, `obtainDistributedTableName,distributedTable=` + this.distributedTable)
161      }
162    } catch (err) {
163      Logger.error(TAG, `ObtainDistributedTableName failed, code is ${err.code},message is ${err.message}`)
164    }
165    this.dataChangeCallback = callback
166    await this.pullData()
167    if (this.rdbStore != undefined) {
168      this.rdbStore.on('dataChange', data_rdb.SubscribeType.SUBSCRIBE_TYPE_REMOTE, async (devices) => {
169        Logger.info(TAG, `on dataChange, callback`)
170        await this.pullData()
171      })
172    }
173  }
174
175  async onDataChangeDetail(device: string, callback: Function) {
176    Logger.info(TAG, `onDataChangeDetail enter,device=` + device + ` ,tableName = ` + this.tableName);
177    try {
178      if (this.rdbStore != undefined) {
179        this.distributedTable = await this.rdbStore.obtainDistributedTableName(device, this.tableName);
180        Logger.info(TAG, `obtainDistributedTableName,distributedTable=` + this.distributedTable);
181      }
182    } catch (err) {
183      Logger.error(TAG, `ObtainDistributedTableName failed, code is ${err.code},message is ${err.message}`);
184    }
185    this.dataChangeDetailCallback = callback;
186    if (this.rdbStore != undefined) {
187      this.rdbStore.on('dataChange', data_rdb.SubscribeType.SUBSCRIBE_TYPE_LOCAL_DETAILS, async (changeInfo: Array<data_rdb.ChangeInfo>) => {
188        Logger.info(TAG, `on dataChange SUBSCRIBE_TYPE_REMOTE, callback`);
189        Logger.info(TAG, `on dataChange SUBSCRIBE_TYPE_REMOTE =` + JSON.stringify(changeInfo));
190        await this.pullDataDetail(changeInfo);
191      })
192    }
193  }
194
195  async pullData() {
196    Logger.info(TAG, `start pullData`)
197    if (this.rdbStore != undefined) {
198      await this.rdbStore.executeSql('delete from ' + this.tableName)
199      let predicates = new data_rdb.RdbPredicates(this.distributedTable)
200      let resultSet = await this.rdbStore.query(predicates, this.columns)
201      let result = this.getListFromResultSet(resultSet)
202      Logger.info(TAG, `on dataChange,result.length=${result.length}`)
203      for (let i = 0; i < result.length; i++) {
204        Logger.info(TAG, `on dataChange,insert${result[i].name}`)
205        let predicate = new data_rdb.RdbPredicates(this.tableName)
206        predicate.equalTo('name', result[i].name)
207        let exit = await this.rdbStore.query(predicate, this.columns)
208        exit.goToFirstRow()
209        if (exit.rowCount === 0) {
210          await this.insertData(result[i])
211        } else {
212          result[i].id = exit.getDouble(resultSet.getColumnIndex('id'))
213          await this.updateData(result[i])
214        }
215      }
216      if (this.dataChangeCallback != null) {
217        this.dataChangeCallback(result)
218      }
219    }
220  }
221
222  async pullDataDetail(changeInfo: Array<data_rdb.ChangeInfo>) {
223    Logger.info(TAG, `start pullDataDetail`);
224    if (this.rdbStore != undefined) {
225      if (changeInfo.length > 0) {
226        let result: Contact[] = [];
227        for (let i = 0; i < changeInfo.length; i++) {
228          let table: string = changeInfo[i].table;
229          if (table !== TABLE_NAME) {
230            return;
231          }
232          let inserted: Array<string> | Array<number> = changeInfo[i].inserted;
233          let updated: Array<string> | Array<number> = changeInfo[i].updated;
234          let deleted: Array<string> | Array<number> = changeInfo[i].deleted;
235          if (inserted.length > 0) {
236            let insertData: Contact[] = await this.getDetailByType(inserted, TYPE_INSERT);
237            insertData.forEach(element => {
238              result.push(element);
239            });
240          }
241          if (updated.length > 0) {
242            let updateData: Contact[] = await this.getDetailByType(updated, TYPE_UPDATE);
243            updateData.forEach(element => {
244              result.push(element);
245            });
246          }
247          if (deleted.length > 0) {
248            for (let index = 0; index < deleted.length; index++) {
249              result.push(new Contact(deleted[index] as number, '', 0, '', 0, '', TYPE_DELETE));
250            }
251          }
252        }
253        Logger.info(TAG, `result:` + JSON.stringify(result));
254        if (this.dataChangeDetailCallback !== null) {
255          this.dataChangeDetailCallback(result);
256        }
257      }
258    }
259  }
260
261  async getDetailByType(id: Array<string> | Array<number>, type: string): Promise<Array<Contact>> {
262    let predicates = new data_rdb.RdbPredicates(TABLE_NAME);
263    predicates.in('id', id);
264    let aData = await this.query(predicates);
265    Logger.info(TAG, `type:${type}`);
266    Logger.info(TAG, `aData:` + JSON.stringify(aData));
267    if (aData.length > 0) {
268      for (let i = 0; i < aData.length; i++) {
269        aData[i].type = type;
270      }
271    }
272    return aData;
273  }
274
275  offDataChange() {
276    if (this.rdbStore != undefined) {
277      this.rdbStore.off('dataChange', data_rdb.SubscribeType.SUBSCRIBE_TYPE_REMOTE, (devices) => {
278        for (let i = 0; i < devices.length; i++) {
279          Logger.info(TAG, `device=${devices[i]} off data changed`)
280        }
281      })
282    }
283  }
284
285  offDataChangeDetail() {
286    if (this.rdbStore != undefined) {
287      this.rdbStore.off('dataChange', data_rdb.SubscribeType.SUBSCRIBE_TYPE_LOCAL_DETAILS, (devices) => {
288        for (let i = 0; i < devices.length; i++) {
289          Logger.info(TAG, `device=${devices[i]} off data changed`)
290        }
291      })
292    }
293  }
294
295  // 处理数据格式
296  getListFromResultSet(resultSet: data_rdb.ResultSet): Contact[] {
297    // 声明结果变量
298    let contacts: Contact[] = []
299    // 进入结果集的第一行
300    resultSet.goToFirstRow()
301    // 如果没有结束就继续遍历
302    while (!resultSet.isEnded) {
303      // 读取各个属性,初始化临时变量contact
304      let contact: Contact = new Contact(resultSet.getDouble(resultSet.getColumnIndex('id'))
305        , resultSet.getString(resultSet.getColumnIndex('name'))
306        , resultSet.getDouble(resultSet.getColumnIndex('gender'))
307        , resultSet.getString(resultSet.getColumnIndex('phone'))
308        , resultSet.getLong(resultSet.getColumnIndex('age'))
309        , resultSet.getString(resultSet.getColumnIndex('remark')))
310      if (!contacts.includes(contact)) {
311        // 如果数据集合中没有这条数据就添加进去
312        contacts.push(contact)
313      }
314      // 进入下一行
315      resultSet.goToNextRow()
316    }
317    // 数据整合完毕就释放资源
318    resultSet.close()
319    Logger.info(TAG, 'contacts number is ' + contacts.length)
320    // 返回整合的联系人数据
321    return contacts
322  }
323}