Skip to content

Commit c8c1654

Browse files
authored
feat(session): schema agreement functions and variables (#27)
Signed-off-by: Daniel Boll <danielboll.academico@gmail.com>
1 parent beb5561 commit c8c1654

File tree

4 files changed

+114
-4
lines changed

4 files changed

+114
-4
lines changed

index.d.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ export interface ClusterConfig {
1515
keyspace?: string
1616
auth?: Auth
1717
ssl?: Ssl
18+
/** The driver automatically awaits schema agreement after a schema-altering query is executed. Waiting for schema agreement more than necessary is never a bug, but might slow down applications which do a lot of schema changes (e.g. a migration). For instance, in case where somebody wishes to create a keyspace and then a lot of tables in it, it makes sense only to wait after creating a keyspace and after creating all the tables rather than after every query. */
19+
autoAwaitSchemaAgreement?: boolean
20+
/** If the schema is not agreed upon, the driver sleeps for a duration in seconds before checking it again. The default value is 0.2 (200 milliseconds) */
21+
schemaAgreementInterval?: number
1822
}
1923
export const enum Consistency {
2024
Any = 0,
@@ -134,6 +138,34 @@ export class ScyllaSession {
134138
* ```
135139
*/
136140
useKeyspace(keyspaceName: string, caseSensitive?: boolean | undefined | null): Promise<void>
141+
/**
142+
* session.awaitSchemaAgreement returns a Promise that can be awaited as long as schema is not in an agreement.
143+
* However, it won’t wait forever; ClusterConfig defines a timeout that limits the time of waiting. If the timeout elapses,
144+
* the return value is an error, otherwise it is the schema_version.
145+
*
146+
* # Returns
147+
*
148+
* * `Promise<Uuid>` - schema_version
149+
*
150+
* # Errors
151+
* * `GenericFailure` - if the timeout elapses
152+
*
153+
* # Example
154+
* ```javascript
155+
* import { Cluster } from ".";
156+
*
157+
* const cluster = new Cluster({ nodes: ["127.0.0.1:9042"] });
158+
* const session = await cluster.connect();
159+
*
160+
* const schemaVersion = await session.awaitSchemaAgreement().catch(console.error);
161+
* console.log(schemaVersion);
162+
*
163+
* const isAgreed = await session.checkSchemaAgreement().catch(console.error);
164+
* console.log(isAgreed);
165+
* ```
166+
*/
167+
awaitSchemaAgreement(): Promise<Uuid>
168+
checkSchemaAgreement(): Promise<boolean>
137169
}
138170
export class Uuid {
139171
/** Generates a random UUID v4. */

src/cluster/cluster_config/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@ pub struct ClusterConfig {
1212
pub compression: Option<Compression>,
1313
pub default_execution_profile: Option<ExecutionProfile>,
1414

15-
// connection fields
1615
pub keyspace: Option<String>,
1716
pub auth: Option<Auth>,
1817
pub ssl: Option<Ssl>,
18+
19+
/// The driver automatically awaits schema agreement after a schema-altering query is executed. Waiting for schema agreement more than necessary is never a bug, but might slow down applications which do a lot of schema changes (e.g. a migration). For instance, in case where somebody wishes to create a keyspace and then a lot of tables in it, it makes sense only to wait after creating a keyspace and after creating all the tables rather than after every query.
20+
pub auto_await_schema_agreement: Option<bool>,
21+
/// If the schema is not agreed upon, the driver sleeps for a duration in seconds before checking it again. The default value is 0.2 (200 milliseconds)
22+
pub schema_agreement_interval: Option<i32>,
1923
}

src/cluster/scylla_cluster.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::time::Duration;
2+
13
use napi::Either;
24
use openssl::ssl::SslContextBuilder;
35

@@ -14,6 +16,8 @@ struct ScyllaCluster {
1416
uri: String,
1517
compression: Option<Compression>,
1618
default_execution_profile: Option<ExecutionProfile>,
19+
auto_await_schema_agreement: Option<bool>,
20+
schema_agreement_interval: Option<Duration>,
1721

1822
// connection fields
1923
connection: Option<ConnectionOptions>,
@@ -61,6 +65,8 @@ impl ScyllaCluster {
6165
keyspace,
6266
auth,
6367
ssl,
68+
auto_await_schema_agreement,
69+
schema_agreement_interval,
6470
} = cluster_config;
6571

6672
let uri = nodes.first().expect("at least one node is required");
@@ -74,6 +80,8 @@ impl ScyllaCluster {
7480
auth,
7581
ssl,
7682
}),
83+
auto_await_schema_agreement,
84+
schema_agreement_interval: schema_agreement_interval.map(|d| Duration::from_secs(d as u64)),
7785
}
7886
}
7987

@@ -152,7 +160,7 @@ impl ScyllaCluster {
152160
} else {
153161
Ok(options.ssl.clone())
154162
}
155-
},
163+
}
156164
(Some(Either::B(_)), Some(_)) => Err(napi::Error::new(
157165
napi::Status::InvalidArg,
158166
"Options cannot be provided twice",
@@ -163,14 +171,14 @@ impl ScyllaCluster {
163171
} else {
164172
Ok(options.ssl.clone())
165173
}
166-
},
174+
}
167175
(None, Some(options)) => {
168176
if options.ssl.is_none() {
169177
Ok(self.connection.as_ref().and_then(|conn| conn.ssl.clone()))
170178
} else {
171179
Ok(options.ssl.clone())
172180
}
173-
},
181+
}
174182
(None, None) => Ok(self.connection.as_ref().and_then(|conn| conn.ssl.clone())),
175183
(Some(Either::A(_)), None) => Ok(self.connection.as_ref().and_then(|conn| conn.ssl.clone())),
176184
};
@@ -212,6 +220,14 @@ impl ScyllaCluster {
212220
));
213221
}
214222

223+
if let Some(auto_await_schema_agreement) = self.auto_await_schema_agreement {
224+
builder = builder.auto_await_schema_agreement(auto_await_schema_agreement);
225+
}
226+
227+
if let Some(schema_agreement_interval) = self.schema_agreement_interval {
228+
builder = builder.schema_agreement_interval(schema_agreement_interval);
229+
}
230+
215231
builder = builder.ssl_context(Some(ssl_builder.build()));
216232
}
217233

src/session/scylla_session.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,62 @@ impl ScyllaSession {
146146

147147
Ok(())
148148
}
149+
150+
/// session.awaitSchemaAgreement returns a Promise that can be awaited as long as schema is not in an agreement.
151+
/// However, it won’t wait forever; ClusterConfig defines a timeout that limits the time of waiting. If the timeout elapses,
152+
/// the return value is an error, otherwise it is the schema_version.
153+
///
154+
/// # Returns
155+
///
156+
/// * `Promise<Uuid>` - schema_version
157+
///
158+
/// # Errors
159+
/// * `GenericFailure` - if the timeout elapses
160+
///
161+
/// # Example
162+
/// ```javascript
163+
/// import { Cluster } from ".";
164+
///
165+
/// const cluster = new Cluster({ nodes: ["127.0.0.1:9042"] });
166+
/// const session = await cluster.connect();
167+
///
168+
/// const schemaVersion = await session.awaitSchemaAgreement().catch(console.error);
169+
/// console.log(schemaVersion);
170+
///
171+
/// const isAgreed = await session.checkSchemaAgreement().catch(console.error);
172+
/// console.log(isAgreed);
173+
/// ```
174+
#[napi]
175+
pub async fn await_schema_agreement(&self) -> napi::Result<Uuid> {
176+
Ok(
177+
self
178+
.session
179+
.await_schema_agreement()
180+
.await
181+
.map_err(|e| {
182+
napi::Error::new(
183+
napi::Status::GenericFailure,
184+
format!("Something went wrong with your schema agreement. - {e}"),
185+
)
186+
})?
187+
.into(),
188+
)
189+
}
190+
191+
#[napi]
192+
pub async fn check_schema_agreement(&self) -> napi::Result<bool> {
193+
Ok(
194+
self
195+
.session
196+
.check_schema_agreement()
197+
.await
198+
.map_err(|e| {
199+
napi::Error::new(
200+
napi::Status::GenericFailure,
201+
format!("Something went wrong with your schema agreement. - {e}"),
202+
)
203+
})?
204+
.is_some(),
205+
)
206+
}
149207
}

0 commit comments

Comments
 (0)