pub struct Table { /* private fields */ }Expand description
A table selected for writes or catalog reads.
The table must already exist for writes. Database and schema default to
scopedb and public; override them with Self::with_database and
Self::with_schema.
Implementations§
Source§impl Table
impl Table
Sourcepub fn with_database(self, database: impl Into<String>) -> Self
pub fn with_database(self, database: impl Into<String>) -> Self
Examples found in repository?
50pub fn write_table(client: &Client) -> Result<Table, io::Error> {
51 let table = std::env::var("SCOPEDB_TABLE")
52 .ok()
53 .filter(|value| !value.is_empty())
54 .ok_or_else(|| {
55 io::Error::new(
56 io::ErrorKind::InvalidInput,
57 "set SCOPEDB_TABLE to a disposable table before running this write example",
58 )
59 })?;
60
61 Ok(client
62 .table(table)
63 .with_database(database())
64 .with_schema(schema()))
65}More examples
18async fn main() -> Result<(), Box<dyn std::error::Error>> {
19 let client = common::client()?;
20 let table_name = std::env::var("SCOPEDB_TABLE").unwrap_or_else(|_| "events".to_string());
21 let table = client
22 .table(table_name)
23 .with_database(common::database())
24 .with_schema(common::schema());
25
26 println!("identifier: {}", table.identifier());
27
28 let description = table.catalog().get().await?.definition;
29 for column in description.columns {
30 println!("{}: {:?}", column.name, column.data_type);
31 }
32
33 Ok(())
34}Sourcepub fn with_schema(self, schema: impl Into<String>) -> Self
pub fn with_schema(self, schema: impl Into<String>) -> Self
Examples found in repository?
50pub fn write_table(client: &Client) -> Result<Table, io::Error> {
51 let table = std::env::var("SCOPEDB_TABLE")
52 .ok()
53 .filter(|value| !value.is_empty())
54 .ok_or_else(|| {
55 io::Error::new(
56 io::ErrorKind::InvalidInput,
57 "set SCOPEDB_TABLE to a disposable table before running this write example",
58 )
59 })?;
60
61 Ok(client
62 .table(table)
63 .with_database(database())
64 .with_schema(schema()))
65}More examples
18async fn main() -> Result<(), Box<dyn std::error::Error>> {
19 let client = common::client()?;
20 let table_name = std::env::var("SCOPEDB_TABLE").unwrap_or_else(|_| "events".to_string());
21 let table = client
22 .table(table_name)
23 .with_database(common::database())
24 .with_schema(common::schema());
25
26 println!("identifier: {}", table.identifier());
27
28 let description = table.catalog().get().await?.definition;
29 for column in description.columns {
30 println!("{}: {:?}", column.name, column.data_type);
31 }
32
33 Ok(())
34}Sourcepub fn identifier(&self) -> String
pub fn identifier(&self) -> String
Examples found in repository?
18async fn main() -> Result<(), Box<dyn std::error::Error>> {
19 let client = common::client()?;
20 let table_name = std::env::var("SCOPEDB_TABLE").unwrap_or_else(|_| "events".to_string());
21 let table = client
22 .table(table_name)
23 .with_database(common::database())
24 .with_schema(common::schema());
25
26 println!("identifier: {}", table.identifier());
27
28 let description = table.catalog().get().await?.definition;
29 for column in description.columns {
30 println!("{}: {:?}", column.name, column.data_type);
31 }
32
33 Ok(())
34}pub async fn drop(&self) -> Result<(), Error>
Sourcepub async fn append(
&self,
ndjson: impl Into<String>,
) -> Result<AppendRowsResult, Error>
pub async fn append( &self, ndjson: impl Into<String>, ) -> Result<AppendRowsResult, Error>
Writes newline-delimited JSON to this table in one HTTP attempt.
Each line must be a JSON object matching the destination columns. A request allows at most 8 MiB of uncompressed NDJSON and 200,000 rows. The SDK sends it with zstd compression and does not automatically retry it.
Integer inputs must fit in a signed 64-bit integer, including values in
uint columns and nested JSON. Larger integers are rejected without
narrowing; query results still support the full u64 range.
let result = client
.table("events")
.append(r#"{"id": 1, "name": "page_view"}"#)
.await?;
println!("Written: {} rows", result.num_rows_inserted);Examples found in repository?
21async fn main() -> Result<(), Box<dyn std::error::Error>> {
22 let client = common::client()?;
23 let table = common::write_table(&client)?;
24
25 // Direct append sends exactly one caller-owned NDJSON request. Each value
26 // is serialized as one line; JSON arrays are not accepted by this API.
27 let ndjson = [
28 serde_json::json!({
29 "id": 1,
30 "occurred_at": jiff::Timestamp::now(),
31 "name": "first",
32 }),
33 serde_json::json!({
34 "id": 2,
35 "occurred_at": jiff::Timestamp::now(),
36 "name": "second",
37 }),
38 ]
39 .iter()
40 .map(serde_json::to_string)
41 .collect::<Result<Vec<_>, _>>()?
42 .join("\n");
43
44 match table.append(ndjson).await {
45 Ok(result) => {
46 println!("committed remotely: {} rows", result.num_rows_inserted);
47 Ok(())
48 }
49 Err(error) => {
50 if error.kind() == ErrorKind::AppendRowsFailed
51 && matches!(
52 error.append_details().map(|details| details.status),
53 Some(AppendState::Unknown)
54 )
55 {
56 eprintln!("commit outcome is unknown; reconcile before replaying this payload");
57 }
58 Err(error.into())
59 }
60 }
61}Sourcepub fn append_stream(&self) -> AppendStreamBuilder
pub fn append_stream(&self) -> AppendStreamBuilder
Builds an asynchronous, bounded and concurrent append stream for this table.
Examples found in repository?
18async fn main() -> Result<(), Box<dyn std::error::Error>> {
19 let client = common::client()?;
20 let table = common::write_table(&client)?;
21 let stream = table.append_stream().build()?;
22
23 let admitted = stream
24 .send_all([
25 serde_json::json!({
26 "id": 1,
27 "occurred_at": jiff::Timestamp::now(),
28 "name": "first",
29 }),
30 serde_json::json!({
31 "id": 2,
32 "occurred_at": jiff::Timestamp::now(),
33 "name": "second",
34 }),
35 ])
36 .await?;
37 println!("accepted locally: {} rows", admitted.accepted_rows);
38
39 // send_all() confirms only local admission. With the default strict policy,
40 // successful shutdown confirms at least one commit acknowledgement per row.
41 // Retrying an unknown outcome can insert duplicates.
42 let report = stream.shutdown().await?;
43 println!("committed remotely: {} rows", report.committed_rows);
44
45 Ok(())
46}More examples
23async fn main() -> Result<(), Box<dyn std::error::Error>> {
24 let path = std::env::args()
25 .nth(1)
26 .ok_or("usage: import_ndjson <events.ndjson>")?;
27 let mut input = BufReader::new(File::open(path)?);
28 let client = common::client()?;
29 let stream = common::write_table(&client)?.append_stream().build()?;
30 let admitted: Result<(), Box<dyn std::error::Error>> = async {
31 let mut line_number = 0;
32 loop {
33 // Bound a single input record as well as the stream's queued bytes.
34 let mut line = String::new();
35 let bytes = input
36 .by_ref()
37 .take(8 * 1024 * 1024 + 1)
38 .read_line(&mut line)?;
39 if bytes == 0 {
40 break;
41 }
42 line_number += 1;
43 if bytes > 8 * 1024 * 1024 {
44 return Err(format!("line {line_number} exceeds 8 MiB").into());
45 }
46 if line.trim().is_empty() {
47 continue;
48 }
49 let row: serde_json::Value = serde_json::from_str(&line)
50 .map_err(|error| format!("line {line_number}: {error}"))?;
51 stream.send(&row).await?;
52 }
53 Ok(())
54 }
55 .await;
56 // Settle the accepted prefix even if parsing or admission failed midway.
57 let settled = stream.shutdown().await;
58 println!("delivery: {:?}", stream.stats());
59 settled?;
60 admitted?;
61 Ok(())
62}43async fn main() -> Result<(), Box<dyn std::error::Error>> {
44 let client = common::client()?;
45 let table = common::write_table(&client)?;
46
47 // Continue mode is explicitly best effort: failed or ambiguous batches are
48 // accounted for, released, and do not stop later telemetry batches.
49 let telemetry = table
50 .append_stream()
51 .failure_policy(AppendFailurePolicy::Continue)
52 .circuit_breaker(Some(AppendCircuitBreakerOptions::default()))
53 .target_batch_bytes(1024 * 1024)
54 .max_batch_rows(10_000)
55 .flush_interval(Duration::from_secs(1))
56 .max_buffered_bytes(32 * 1024 * 1024)
57 // This limit applies to each stream; include every application replica.
58 .max_concurrent_batches(1)
59 .attempt_timeout(Duration::from_secs(10))
60 .on_batch_failure(|event| {
61 // A synchronous observer; use a separate diagnostics sink.
62 eprintln!("telemetry append failure: {event:?}");
63 })
64 .build()?;
65
66 let mut dropped_locally = 0_u64;
67 for request in 1..=100 {
68 if !track(&telemetry, request) {
69 dropped_locally += 1;
70 }
71 }
72 println!("locally dropped: {dropped_locally}");
73
74 // In a service, stop and join producer tasks before this settlement barrier.
75 let report = telemetry.shutdown().await?;
76 if report.outcome != AppendDeliveryOutcome::Ok {
77 eprintln!("telemetry loss or ambiguity: {report:?}");
78 }
79 println!("final stream stats: {:?}", telemetry.stats());
80
81 Ok(())
82}22async fn main() -> Result<(), Box<dyn std::error::Error>> {
23 let client = common::client()?;
24 let table = common::write_table(&client)?;
25
26 // The default Stop policy gives strict barriers. Local memory and request
27 // concurrency are bounded independently; concurrent batches have no
28 // defined commit order.
29 let stream = table
30 .append_stream()
31 .target_batch_bytes(32 * 1024)
32 .max_batch_rows(10_000)
33 .flush_interval(Duration::from_secs(1))
34 .max_buffered_bytes(1024 * 1024)
35 .max_concurrent_batches(4)
36 .attempt_timeout(Duration::from_secs(30))
37 .build()?;
38
39 let rows = (1..=10_000).map(|id| {
40 serde_json::json!({
41 "id": id,
42 "occurred_at": jiff::Timestamp::now(),
43 "name": format!("example-{id}"),
44 })
45 });
46
47 let admission_error = match stream.send_all(rows).await {
48 Ok(result) => {
49 println!("accepted locally: {} rows", result.accepted_rows);
50 None
51 }
52 Err(error) => {
53 // There is no stream-wide abort or rollback. Settle the already
54 // accepted prefix even if row production or admission stopped.
55 eprintln!("row admission stopped; settling the accepted prefix: {error}");
56 Some(error)
57 }
58 };
59
60 match stream.shutdown().await {
61 Ok(report) => {
62 println!("committed remotely: {} rows", report.committed_rows);
63 println!("final stream stats: {:?}", stream.stats());
64 }
65 Err(error) => {
66 if matches!(
67 error.append_details().map(|details| details.status),
68 Some(AppendState::Unknown)
69 ) {
70 eprintln!("commit outcome is unknown; reconcile before replaying");
71 } else {
72 eprintln!("bulk append failed: {error}");
73 }
74 eprintln!("final stream stats: {:?}", stream.stats());
75 return Err(error.into());
76 }
77 }
78
79 if let Some(error) = admission_error {
80 return Err(error.into());
81 }
82 Ok(())
83}Sourcepub fn catalog(&self) -> CatalogResource<CatalogTable>
pub fn catalog(&self) -> CatalogResource<CatalogTable>
Selects this table’s complete definition and ETag for conditional changes.
Examples found in repository?
18async fn main() -> Result<(), Box<dyn std::error::Error>> {
19 let client = common::client()?;
20 let table_name = std::env::var("SCOPEDB_TABLE").unwrap_or_else(|_| "events".to_string());
21 let table = client
22 .table(table_name)
23 .with_database(common::database())
24 .with_schema(common::schema());
25
26 println!("identifier: {}", table.identifier());
27
28 let description = table.catalog().get().await?.definition;
29 for column in description.columns {
30 println!("{}: {:?}", column.name, column.data_type);
31 }
32
33 Ok(())
34}