rust.mdx 11.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
---
toc_max_heading_level: 4
sidebar_position: 5
sidebar_label: Rust
title: TDengine Rust Connector
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

import Preparation from "./_preparation.mdx"
import RustInsert from "../../07-develop/03-insert-data/_rust_sql.mdx"
import RustInfluxLine from "../../07-develop/03-insert-data/_rust_line.mdx"
import RustOpenTSDBTelnet from "../../07-develop/03-insert-data/_rust_opts_telnet.mdx"
import RustOpenTSDBJson from "../../07-develop/03-insert-data/_rust_opts_json.mdx"
import RustQuery from "../../07-develop/04-query-data/_rust.mdx"

`libtaos` is the official Rust language connector for TDengine. Rust developers can develop applications to access the TDengine instance data.

`libtaos` provides two ways to establish connections. One is the **Native Connection**, which connects to TDengine instances via the TDengine client driver (taosc). The other is **REST connection**, which connects to TDengine instances via taosAdapter's REST interface.

The source code for `libtaos` is hosted on [GitHub](https://github.com/taosdata/libtaos-rs).

## Supported platforms

The platforms supported by native connections are the same as those supported by the TDengine client driver.
REST connections are supported on all platforms that can run Rust.

## Version support

Please refer to [version support list](/reference/connector#version-support).

33
The Rust Connector is still under rapid development and is not guaranteed to be backward compatible before 1.0. We recommend using TDengine version 2.4 or higher to avoid known issues.
34 35 36 37 38 39 40 41 42 43 44 45 46 47

## Installation

### Pre-installation
* Install the Rust development toolchain
* If using the native connection, please install the TDengine client driver. Please refer to [install client driver](/reference/connector#install-client-driver)

### Adding libtaos dependencies

Add the [libtaos][libtaos] dependency to the [Rust](https://rust-lang.org) project as follows, depending on the connection method selected.

<Tabs defaultValue="native">
<TabItem value="native" label="native connection">

D
dingbo 已提交
48
Add [libtaos][libtaos] to the `Cargo.toml` file.
49

D
dingbo 已提交
50
```toml
51 52 53 54 55
[dependencies]
# use default feature
libtaos = "*"
```

D
dingbo 已提交
56
</TabItem>
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
<TabItem value="rest" label="REST connection">

Add [libtaos][libtaos] to the `Cargo.toml` file and enable the `rest` feature.

```toml
[dependencies]
# use rest feature
libtaos = { version = "*", features = ["rest"]}
```

</TabItem>
</Tabs>


### Using connection pools

Please enable the `r2d2` feature in `Cargo.toml`.

```toml
[dependencies]
# with taosc
libtaos = { version = "*", features = ["r2d2"] }
# or rest
libtaos = { version = "*", features = ["rest", "r2d2"] }
```

## Create a connection

The [TaosCfgBuilder] provides the user with an API in the form of a constructor for the subsequent creation of connections or use of connection pools.

```rust
let cfg: TaosCfg = TaosCfgBuilder::default()
    .ip("127.0.0.1")
    .user("root")
    .pass("taosdata")
    .db("log") // do not set if not require a default database.
    .port(6030u16)
    .build()
    .expect("TaosCfg builder error");
}
```

You can now use this object to create the connection.

```rust
let conn = cfg.connect()? ;
```

The connection object can create more than one.

```rust
let conn = cfg.connect()? ;
let conn2 = cfg.connect()? ;
```

You can use connection pools in applications.

```rust
let pool = r2d2::Pool::builder()
    .max_size(10000) // max connections
    .build(cfg)? ;

// ...
// Use pool to get connection
let conn = pool.get()? ;
```

After that, you can perform the following operations on the database.

```rust
async fn demo() -> Result<(), Error> {
    // get connection ...

    // create database
    conn.exec("create database if not exists demo").await?
    // change database context
    conn.exec("use demo").await?
    // create table
    conn.exec("create table if not exists tb1 (ts timestamp, v int)").await?
    // insert
    conn.exec("insert into tb1 values(now, 1)").await?
    // query
    let rows = conn.query("select * from tb1").await?
    for row in rows.rows {
        println!("{}", row.into_iter().join(","));
    }
}
```

## Usage examples

### Write data

#### SQL Write

<RustInsert />

#### InfluxDB line protocol write

<RustInfluxLine />

#### OpenTSDB Telnet line protocol write

<RustOpenTSDBTelnet />

#### OpenTSDB JSON line protocol write

<RustOpenTSDBJson />

### Query data

<RustQuery />

### More sample programs

| Program Path | Program Description |
| -------------- | ----------------------------------------------------------------------------- |
| [demo.rs] | Basic API Usage Examples |
| [bailongma-rs] | Using TDengine as the Prometheus remote storage API adapter for the storage backend, using the r2d2 connection pool |

## API Reference

### Connection constructor API

The [Builder Pattern](https://doc.rust-lang.org/1.0.0/style/ownership/builders.html) constructor pattern is Rust's solution for handling complex data types or optional configuration types. The [libtaos] implementation uses the connection constructor [TaosCfgBuilder] as the entry point for the TDengine Rust connector. The [TaosCfgBuilder] provides optional configuration of servers, ports, databases, usernames, passwords, etc.

Using the `default()` method, you can construct a [TaosCfg] with default parameters for subsequent connections to the database or establishing connection pools.

```rust
let cfg = TaosCfgBuilder::default().build()? ;
```

Using the constructor pattern, the user can set on-demand.

```rust
let cfg = TaosCfgBuilder::default()
    .ip("127.0.0.1")
    .user("root")
    .pass("taosdata")
    .db("log")
    .port(6030u16)
    .build()? ;
```

Create TDengine connection using [TaosCfg] object.

```rust
let conn: Taos = cfg.connect();
```

### Connection pooling

209
In complex applications, we recommend enabling connection pools. Connection pool for [libtaos] is implemented using [r2d2].
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252

As follows, a connection pool with default parameters can be generated.

```rust
let pool = r2d2::Pool::new(cfg)? ;
```

You can set the same connection pool parameters using the connection pool's constructor.

```rust
    use std::time::Duration;
    let pool = r2d2::Pool::builder()
        .max_size(5000) // max connections
        .max_lifetime(Some(Duration::from_minutes(100))) // lifetime of each connection
        .min_idle(Some(1000)) // minimal idle connections
        .connection_timeout(Duration::from_minutes(2))
        .build(cfg);
```

In the application code, use `pool.get()? ` to get a connection object [Taos].

```rust
let taos = pool.get()? ;
```

The [Taos] structure is the connection manager in [libtaos] and provides two main APIs.

1. `exec`: Execute some non-query SQL statements, such as `CREATE`, `ALTER`, `INSERT`, etc.

    ```rust
    taos.exec().await?
    ```

2. `query`: Execute the query statement and return the [TaosQueryData] object.

    ```rust
    let q = taos.query("select * from log.logs").await?
    ```

    The [TaosQueryData] object stores the query result data and basic information about the returned columns (column name, type, length).

    Column information is stored using [ColumnMeta].

D
dingbo 已提交
253
    ```rust
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
    let cols = &q.column_meta;
    for col in cols {
        println!("name: {}, type: {:?} , bytes: {}", col.name, col.type_, col.bytes);
    }
    ```

    It fetches data line by line.

    ```rust
    for (i, row) in q.rows.iter().enumerate() {
        for (j, cell) in row.iter().enumerate() {
            println!("cell({}, {}) data: {}", i, j, cell);
        }
    }
    ```

Note that Rust asynchronous functions and an asynchronous runtime are required.

272
[Taos] provides a few Rust methods that encapsulate SQL to reduce the frequency of `format!` code blocks.
273 274 275 276 277 278 279 280 281

- `.describe(table: &str)`: Executes `DESCRIBE` and returns a Rust data structure.
- `.create_database(database: &str)`: Executes the `CREATE DATABASE` statement.
- `.use_database(database: &str)`: Executes the `USE` statement.

In addition, this structure is also the entry point for [Parameter Binding](#Parameter Binding Interface) and [Line Protocol Interface](#Line Protocol Interface). Please refer to the specific API descriptions for usage.

### Bind Interface

282
Similar to the C interface, Rust provides the bind interface's wrapping. First, create a bind object [Stmt] for a SQL command from the [Taos] object.
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384

```rust
let mut stmt: Stmt = taos.stmt("insert into ? values(? ,?)") ? ;
```

The bind object provides a set of interfaces for implementing parameter binding.

##### `.set_tbname(tbname: impl ToCString)`

To bind table names.

##### `.set_tbname_tags(tbname: impl ToCString, tags: impl IntoParams)`

Bind sub-table table names and tag values when the SQL statement uses a super table.

```rust
let mut stmt = taos.stmt("insert into ? using stb0 tags(?) values(? ,?)") ? ;
// tags can be created with any supported type, here is an example using JSON
let v = Field::Json(serde_json::from_str("{\"tag1\":\"one, two, three, four, five, six, seven, eight, nine, ten\"}").unwrap());
stmt.set_tbname_tags("tb0", [&tag])? ;
```

##### `.bind(params: impl IntoParams)`

Bind value types. Use the [Field] structure to construct the desired type and bind.

```rust
let ts = Field::Timestamp(Timestamp::now());
let value = Field::Float(0.0);
stmt.bind(vec![ts, value].iter())? ;
```

##### `.execute()`

Execute SQL.[Stmt] objects can be reused, re-binded, and executed after execution.

```rust
stmt.execute()? ;

// next bind cycle.
// stmt.set_tbname()? ;
//stmt.bind()? ;
//stmt.execute()? ;
```

### Line protocol interface

The line protocol interface supports multiple modes and different precision and requires the introduction of constants in the schemaless module to set.

```rust
use libtaos::*;
use libtaos::schemaless::*;
```

- InfluxDB line protocol

    ```rust
    let lines = [
        "st,t1=abc,t2=def,t3=anything c1=3i64,c3=L\"pass\",c2=false 1626006833639000000"
        "st,t1=abc,t2=def,t3=anything c1=3i64,c3=L\"abc\",c4=4f64 1626006833639000000"
    ];
    taos.schemaless_insert(&lines, TSDB_SML_LINE_PROTOCOL, TSDB_SML_TIMESTAMP_NANOSECONDS)? ;
    ```

- OpenTSDB Telnet Protocol

    ```rust
    let lines = ["sys.if.bytes.out 1479496100 1.3E3 host=web01 interface=eth0"];
    taos.schemaless_insert(&lines, TSDB_SML_LINE_PROTOCOL, TSDB_SML_TIMESTAMP_SECONDS)? ;
    ```

- OpenTSDB JSON protocol

    ```rust
    let lines = [r#"
        {
            "metric": "st",
            "timestamp": 1626006833,
            "value": 10,
            "tags": {
                "t1": true,
                "t2": false,
                "t3": 10,
                "t4": "123_abc_.! @#$%^&*:;,. /? |+-=()[]{}<>"
            }
        }"#];
    taos.schemaless_insert(&lines, TSDB_SML_LINE_PROTOCOL, TSDB_SML_TIMESTAMP_SECONDS)? ;
    ```

Please move to the Rust documentation hosting page for other related structure API usage instructions: <https://docs.rs/libtaos>.

[libtaos]: https://github.com/taosdata/libtaos-rs
[tdengine]: https://github.com/taosdata/TDengine
[bailongma-rs]: https://github.com/taosdata/bailongma-rs
[r2d2]: https://crates.io/crates/r2d2
[demo.rs]: https://github.com/taosdata/libtaos-rs/blob/main/examples/demo.rs
[TaosCfgBuilder]: https://docs.rs/libtaos/latest/libtaos/struct.TaosCfgBuilder.html
[TaosCfg]: https://docs.rs/libtaos/latest/libtaos/struct.TaosCfg.html
[Taos]: https://docs.rs/libtaos/latest/libtaos/struct.Taos.html
[TaosQueryData]: https://docs.rs/libtaos/latest/libtaos/field/struct.TaosQueryData.html
[Field]: https://docs.rs/libtaos/latest/libtaos/field/enum.Field.html
[Stmt]: https://docs.rs/libtaos/latest/libtaos/stmt/struct.Stmt.html