Skip to content

Commit

Permalink
feat: expose util module and add custom_query.rs example (#98)
Browse files Browse the repository at this point in the history
  • Loading branch information
liufuyang authored Oct 23, 2024
1 parent af101c0 commit a9ce0bf
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 14 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,10 @@ Supported interfaces towards Bigtable:
* [MutateRow](https://github.com/googleapis/googleapis/blob/master/google/bigtable/v2/bigtable.proto#L78)
* [MutateRows](https://github.com/googleapis/googleapis/blob/master/google/bigtable/v2/bigtable.proto#L90)

For other gRPC APIs/methods, one should be able to use the gRCP client directly and assemble the request you need to
For other gRPC APIs/methods, one should be able to use the gRCP client directly and assemble any customized request you
need to
interact with Bigtable service via building the Protobuf messages (already complied as rs files and included here).
See [this example](./examples/src/custom_query.rs).

[gcp_auth](https://github.com/hrvolapeter/gcp_auth) is used, which
supports:
Expand All @@ -63,7 +65,7 @@ You can use the library as follows:

```toml
[dependencies]
bigtable_rs = "0.2.12"
bigtable_rs = "0.2.13"
tokio = { version = "1.0", features = ["rt-multi-thread"] }
env_logger = "0.11.1"
```
Expand Down
2 changes: 1 addition & 1 deletion bigtable_rs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "bigtable_rs"
description = "A very simple Google Bigtable client lib in Rust"
version = "0.2.12"
version = "0.2.13"
authors = ["Fuyang Liu <[email protected]>"]
edition = "2021"
license = "MIT"
Expand Down
5 changes: 3 additions & 2 deletions bigtable_rs/src/bigtable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ use crate::google::bigtable::v2::{
SampleRowKeysResponse,
};
use crate::google::bigtable::v2::{CheckAndMutateRowRequest, CheckAndMutateRowResponse};
use crate::{root_ca_certificate, util::get_end_key};
use crate::{root_ca_certificate, util::get_end_key_for_prefix};

pub mod read_rows;

Expand Down Expand Up @@ -486,7 +486,8 @@ impl BigTable {
mut request: ReadRowsRequest,
prefix: Vec<u8>,
) -> Result<Vec<(RowKey, Vec<RowCell>)>> {
let end_key = get_end_key(prefix.as_ref()).map(|end_key| EndKey::EndKeyOpen(end_key));
let end_key =
get_end_key_for_prefix(prefix.as_ref()).map(|end_key| EndKey::EndKeyOpen(end_key));
request.rows = Some(RowSet {
row_keys: vec![], // use this field to put keys for reading specific rows
row_ranges: vec![RowRange {
Expand Down
2 changes: 1 addition & 1 deletion bigtable_rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mod auth_service;
pub mod bigtable;
pub mod google;
mod root_ca_certificate;
mod util;
pub mod util;

#[cfg(test)]
mod tests {
Expand Down
16 changes: 8 additions & 8 deletions bigtable_rs/src/util.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub(crate) fn get_end_key(start_key: &[u8]) -> Option<Vec<u8>> {
pub fn get_end_key_for_prefix(start_key: &[u8]) -> Option<Vec<u8>> {
let size = start_key.len();
if size < 1 {
return None;
Expand All @@ -24,23 +24,23 @@ pub(crate) fn get_end_key(start_key: &[u8]) -> Option<Vec<u8>> {

#[cfg(test)]
mod tests {
use super::get_end_key;
use super::get_end_key_for_prefix;
#[test]
fn get_end_key_works() {
assert_eq!(get_end_key(&[]), None);
assert_eq!(get_end_key(&[0x01u8]), Some([0x02u8].to_vec()));
assert_eq!(get_end_key_for_prefix(&[]), None);
assert_eq!(get_end_key_for_prefix(&[0x01u8]), Some([0x02u8].to_vec()));
assert_eq!(
get_end_key(&[0x01u8, 0xFFu8]),
get_end_key_for_prefix(&[0x01u8, 0xFFu8]),
Some([0x02u8, 0x00u8].to_vec())
);
assert_eq!(
get_end_key(&[0x21u8, 0xFFu8]),
get_end_key_for_prefix(&[0x21u8, 0xFFu8]),
Some([0x22u8, 0x00u8].to_vec())
);
assert_eq!(
get_end_key(&[0xFFu8, 0xF1u8, 0xFFu8]),
get_end_key_for_prefix(&[0xFFu8, 0xF1u8, 0xFFu8]),
Some([0xFFu8, 0xF2u8, 0x00u8].to_vec())
);
assert_eq!(get_end_key(&[0xFFu8]), None);
assert_eq!(get_end_key_for_prefix(&[0xFFu8]), None);
}
}
4 changes: 4 additions & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ path = "src/configure_inner_client.rs"
name = "prefix"
path = "src/prefix.rs"

[[bin]]
name = "custom_query"
path = "src/custom_query.rs"

[dependencies]
bigtable_rs = { path = "../bigtable_rs" }
tokio = { version = "1.34.0", features = ["rt-multi-thread"] }
Expand Down
90 changes: 90 additions & 0 deletions examples/src/custom_query.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use bigtable_rs::bigtable;
use bigtable_rs::bigtable::read_rows::decode_read_rows_response;
use bigtable_rs::google::bigtable::v2::row_filter::{Chain, Filter};
use bigtable_rs::google::bigtable::v2::row_range::{EndKey, StartKey};
use bigtable_rs::google::bigtable::v2::{ReadRowsRequest, RowFilter, RowRange, RowSet};
use bigtable_rs::util::get_end_key_for_prefix;
use env_logger;
use std::error::Error;
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();

let project_id = "project-1";
let instance_name = "instance-1";
let table_name = "table-1";
let channel_size = 4;
let timeout = Duration::from_secs(10);

let prefix_a: String = "j".to_owned();
let prefix_b: String = "p".to_owned();

// make a bigtable client
let connection = bigtable::BigTableConnection::new(
project_id,
instance_name,
true,
channel_size,
Some(timeout),
)
.await?;
let mut bigtable = connection.client();

// prepare a ReadRowsRequest with fully customized query
let request = ReadRowsRequest {
app_profile_id: "default".to_owned(),
table_name: bigtable.get_full_table_name(table_name),
rows_limit: 20,
rows: Some(RowSet {
row_keys: vec![],
row_ranges: vec![
RowRange {
start_key: Some(StartKey::StartKeyClosed(prefix_a.clone().into_bytes())),
end_key: get_end_key_for_prefix(prefix_a.as_ref()).map(EndKey::EndKeyOpen),
},
RowRange {
start_key: Some(StartKey::StartKeyClosed(prefix_b.clone().into_bytes())),
end_key: get_end_key_for_prefix(prefix_b.as_ref()).map(EndKey::EndKeyOpen),
},
],
}),
filter: Some(RowFilter {
filter: Some(Filter::Chain(Chain {
filters: vec![
RowFilter {
filter: Some(Filter::FamilyNameRegexFilter("cf1".to_owned())),
},
RowFilter {
filter: Some(Filter::ColumnQualifierRegexFilter("c1".as_bytes().to_vec())),
},
RowFilter {
filter: Some(Filter::CellsPerColumnLimitFilter(1)),
},
],
})),
}),
..ReadRowsRequest::default()
};

// calling bigtable API to get results using inner client and customized query
let response_stream = bigtable.get_client().read_rows(request).await?.into_inner();
let response = decode_read_rows_response(&Some(timeout), response_stream).await?;

// simply print results for example usage
response.into_iter().for_each(|(key, data)| {
println!("------------\n{}", String::from_utf8(key.clone()).unwrap());
data.into_iter().for_each(|row_cell| {
println!(
" [{}:{}] \"{}\" @ {}",
row_cell.family_name,
String::from_utf8(row_cell.qualifier).unwrap(),
String::from_utf8(row_cell.value).unwrap(),
row_cell.timestamp_micros
)
})
});

Ok(())
}
14 changes: 14 additions & 0 deletions start_load_table_local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,20 @@ cbt -instance instance-1 -project project-1 set table-1 key4 cf1:c1=value4
cbt -instance instance-1 -project project-1 set table-1 key5 cf1:c1=value5
cbt -instance instance-1 -project project-1 set table-1 key6 cf1:c1=value6

cbt -instance instance-1 -project project-1 set table-1 jey1 cf1:c1=jvalue1
cbt -instance instance-1 -project project-1 set table-1 jey2 cf1:c1=jvalue2
cbt -instance instance-1 -project project-1 set table-1 jey3 cf1:c1=jvalue3
cbt -instance instance-1 -project project-1 set table-1 jey4 cf1:c1=jvalue4
cbt -instance instance-1 -project project-1 set table-1 jey5 cf1:c1=jvalue5
cbt -instance instance-1 -project project-1 set table-1 jey6 cf1:c1=jvalue6

cbt -instance instance-1 -project project-1 set table-1 pey1 cf1:c1=pvalue1
cbt -instance instance-1 -project project-1 set table-1 pey2 cf1:c1=pvalue2
cbt -instance instance-1 -project project-1 set table-1 pey3 cf1:c1=pvalue3
cbt -instance instance-1 -project project-1 set table-1 pey4 cf1:c1=pvalue4
cbt -instance instance-1 -project project-1 set table-1 pey5 cf1:c1=pvalue5
cbt -instance instance-1 -project project-1 set table-1 pey6 cf1:c1=pvalue6

# Set another version into key1
cbt -instance instance-1 -project project-1 set table-1 key1 cf1:c1=value1.v1
cbt -instance instance-1 -project project-1 set table-1 key1 cf1:c2=value1.c2
Expand Down

0 comments on commit a9ce0bf

Please sign in to comment.