# Data Ability Development ## When to Use A Data ability helps applications manage access to data stored by themselves and other applications. It also provides APIs for sharing data with other applications either on the same device or across devices. Data ability providers can customize data access-related APIs such as data inserting, deleting, updating, and querying, as well as file opening, and share data with other applications through these open APIs. ## URI Introduction A Uniform Resource Identifier (URI) is used to identify a specific data item, such as a table in the database or a file on the disk. URIs used in OpenHarmony comply with the commonly used URI standard. A URI consists of the components: ![fa-dataability-uri](figures/fa-dataability-uri.png) - **scheme**: name of the scheme used by the Data ability. The value is fixed at **dataability**. - **authority**: device ID. To access data on a remote device, set this component to the ID of the remote device. To access data on the local device, leave this component empty. - **path**: location of the specific resource to access. - **query**: query parameters. - **fragment**: subordinate resources to access. Example URIs: - Cross-device communication: **dataability://***device_id***/***com.domainname.dataability.persondata***/***person***/***10* - Local-device communication: **dataability:///***com.domainname.dataability.persondata***/***person***/***10* > **NOTE** > > In the case of local-device communication, **device_id** is empty, and therefore, there are three slashes (/) after **dataability:**. ## Available APIs **Table 1** Data ability lifecycle APIs |API|Description| |:------|:------| |onInitialized?(info: AbilityInfo): void|Called during ability initialization to initialize the relational database (RDB).| |update?(uri: string, valueBucket: rdb.ValuesBucket, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback\): void|Updates data in the database.| |query?(uri: string, columns: Array\, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback\): void|Queries data in the database.| |delete?(uri: string, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback\): void|Deletes one or more data records from the database.| |normalizeUri?(uri: string, callback: AsyncCallback\): void|Normalizes the URI. A normalized URI applies to cross-device use, persistence, backup, and restore. When the context changes, it ensures that the same data item can be referenced.| |batchInsert?(uri: string, valueBuckets: Array\, callback: AsyncCallback\): void|Inserts multiple data records into the database.| |denormalizeUri?(uri: string, callback: AsyncCallback\): void|Converts a normalized URI generated by **normalizeUri** into a denormalized URI.| |insert?(uri: string, valueBucket: rdb.ValuesBucket, callback: AsyncCallback\): void|Inserts a data record into the database.| |openFile?(uri: string, mode: string, callback: AsyncCallback\): void|Opens a file.| |getFileTypes?(uri: string, mimeTypeFilter: string, callback: AsyncCallback\>): void|Obtains the MIME type of a file.| |getType?(uri: string, callback: AsyncCallback\): void|Obtains the MIME type matching the data specified by the URI.| |executeBatch?(ops: Array\, callback: AsyncCallback\>): void|Operates data in the database in batches.| |call?(method: string, arg: string, extras: PacMap, callback: AsyncCallback\): void|Calls a custom API.| ## How to Develop ### Creating a Data Ability 1. To meet the basic requirements of the database storage service, implement the **Insert**, **Query**, **Update**, and **Delete** APIs in the **Data** class. The **BatchInsert** and **ExecuteBatch** APIs have already implemented the traversal logic, but not batch data processing. The following code snippet shows how to create a Data ability: ```javascript import dataAbility from '@ohos.data.dataAbility' import dataRdb from '@ohos.data.rdb' const TABLE_NAME = 'book' const STORE_CONFIG = { name: 'book.db' } const SQL_CREATE_TABLE = 'CREATE TABLE IF NOT EXISTS book(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, introduction TEXT NOT NULL)' let rdbStore: dataRdb.RdbStore = undefined export default { onInitialized(abilityInfo) { console.info('DataAbility onInitialized, abilityInfo:' + abilityInfo.bundleName) dataRdb.getRdbStore(STORE_CONFIG, 1, (err, store) => { console.info('DataAbility getRdbStore callback') store.executeSql(SQL_CREATE_TABLE, []) rdbStore = store }); }, insert(uri, valueBucket, callback) { console.info('DataAbility insert start') rdbStore.insert(TABLE_NAME, valueBucket, callback) }, batchInsert(uri, valueBuckets, callback) { console.info('DataAbility batch insert start') for (let i = 0;i < valueBuckets.length; i++) { console.info('DataAbility batch insert i=' + i) if (i < valueBuckets.length - 1) { rdbStore.insert(TABLE_NAME, valueBuckets[i], (err: any, num: number) => { console.info('DataAbility batch insert ret=' + num) }) } else { rdbStore.insert(TABLE_NAME, valueBuckets[i], callback) } } }, query(uri, columns, predicates, callback) { console.info('DataAbility query start') let rdbPredicates = dataAbility.createRdbPredicates(TABLE_NAME, predicates) rdbStore.query(rdbPredicates, columns, callback) }, update(uri, valueBucket, predicates, callback) { console.info('DataAbilityupdate start') let rdbPredicates = dataAbility.createRdbPredicates(TABLE_NAME, predicates) rdbStore.update(valueBucket, rdbPredicates, callback) }, delete(uri, predicates, callback) { console.info('DataAbilitydelete start') let rdbPredicates = dataAbility.createRdbPredicates(TABLE_NAME, predicates) rdbStore.delete(rdbPredicates, callback) } }; ``` 2. Configure the submodule. | JSON Field| Description | | ------------ | ------------------------------------------------------------ | | "name" | Ability name, corresponding to the **Data** class name derived from **Ability**. | | "type" | Ability type, which is **Data** for a Data ability. | | "uri" | URI used for communication. | | "visible" | Whether the Data ability is visible to other applications. When this parameter is set to **true**, the Data ability can communicate with other applications.| **config.json configuration example** ```json "abilities":[{ "srcPath": "DataAbility", "name": ".DataAbility", "icon": "$media:icon", "srcLanguage": "ets", "description": "$string:description_dataability", "type": "data", "visible": true, "uri": "dataability://ohos.samples.etsdataability.DataAbility" }] ``` ### Accessing a Data ability #### Development Preparations Import the basic dependency packages and obtain the URI string for communicating with the Data submodule. The basic dependency packages include: - @ohos.ability.featureAbility - @ohos.data.dataability - @ohos.data.rdb #### Data Ability API Development 1. Create a Data ability helper. For details about the APIs provided by **DataAbilityHelper**, see [DataAbilityHelper Module](../reference/apis/js-apis-dataAbilityHelper.md). ```js // Different from the URI defined in the config.json file, the URI passed in the parameter has an extra slash (/), because there is a DeviceID parameter between the second and the third slash (/). import featureAbility from '@ohos.ability.featureAbility' import ohos_data_ability from '@ohos.data.dataAbility' import ohos_data_rdb from '@ohos.data.rdb' var urivar = "dataability:///com.ix.DataAbility" var DAHelper = featureAbility.acquireDataAbilityHelper( urivar ); ``` 2. Construct RDB data. ```js var valuesBucket = {"name": "gaolu"} var da = new ohos_data_ability.DataAbilityPredicates() var valArray =new Array("value1"); var cars = new Array({"batchInsert1" : "value1",}); ``` 3. Use **insert** to insert data to the Data submodule. ```js // Callback mode: DAHelper.insert( urivar, valuesBucket, (error, data) => { console.log("DAHelper insert result: " + data) } ); ``` ```js // Promise mode: var datainsert = await DAHelper.insert( urivar, valuesBucket ); ``` 4. Use **delete** to delete data from the Data submodule. ```js // Callback mode: DAHelper.delete( urivar, da, (error, data) => { console.log("DAHelper delete result: " + data) } ); ``` ```js // Promise mode: var datadelete = await DAHelper.delete( urivar, da, ); ``` 5. Use **update** to update data in the Data submodule. ```js // Callback mode: DAHelper.update( urivar valuesBucket, da, (error, data) => { console.log("DAHelper update result: " + data) } ); ``` ```js // Promise mode: var dataupdate = await DAHelper.update( urivar, valuesBucket, da, ); ``` 6. Use **query** to query data in the Data submodule. ```js // Callback mode: DAHelper.query( urivar, valArray, da, (error, data) => { console.log("DAHelper query result: " + data) } ); ``` ```js // Promise mode: var dataquery = await DAHelper.query( urivar, valArray, da ); ``` 7. Use **batchInsert** to insert data in batches to the Data submodule. ```js // Callback mode: DAHelper.batchInsert( urivar, cars, (error, data) => { console.log("DAHelper batchInsert result: " + data) } ); ``` ```js // Promise mode: var databatchInsert = await DAHelper.batchInsert( urivar, cars ); ``` 8. Use **executeBatch** to process data in batches in the Data submodule. ```js // Callback mode: DAHelper.executeBatch( urivar, [ { uri: urivar, type: featureAbility.DataAbilityOperationType.TYPE_INSERT, valuesBucket: {"executeBatch" : "value1",}, predicates: da, expectedCount:0, predicatesBackReferences: null, interrupted:true, } ], (error, data) => { console.log("DAHelper executeBatch result: " + data) } ); ``` ```js // Promise mode: var dataexecuteBatch = await DAHelper.executeBatch( urivar, [ { uri: urivar, type: featureAbility.DataAbilityOperationType.TYPE_INSERT, valuesBucket: { "executeBatch" : "value1", }, predicates: da, expectedCount:0, predicatesBackReferences: null, interrupted:true, } ] ); ```