Skip to content

Commit afc3fca

Browse files
Convex, Incnipunn1313
authored andcommitted
Updates to convex-rs
GitOrigin-RevId: d98988dc0210767115c1aca605b7ba1100594718
1 parent 43605c3 commit afc3fca

File tree

10 files changed

+224
-70
lines changed

10 files changed

+224
-70
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Upcoming
22

3+
# 0.5.0
4+
5+
- Prelim support for ConvexError, encoded into an anyhow::Error. Eventual plan
6+
is to expose a separate catchable type, but just getting something out
7+
quickly. PRs accepted!
8+
39
# 0.4.0
410

511
- Expose an alternate cleaner JSON export format on Value. The clean format is

Cargo.toml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "convex"
33
description = "Client library for Convex (convex.dev)"
44
authors = [ "Convex, Inc. <team@convex.dev>" ]
5-
version = "0.4.0"
5+
version = "0.5.0"
66
edition = "2021"
77
rust-version = "1.65.0"
88
resolver = "2"
@@ -15,13 +15,13 @@ anyhow = { version = "1" }
1515
async-trait = { version = "0.1" }
1616
base64 = { version = "0.13" }
1717
bytes = { version = "1.1.0" }
18-
convex_sync_types = { path = "./sync_types", version = "=0.4.0" }
18+
convex_sync_types = { path = "./sync_types", version = "=0.5.0" }
1919
derive_more = { version = "0.99" }
2020
futures = { version = "0.3" }
2121
imbl = { version = "2.0.0" }
2222
parking_lot = { optional = true, version = "0.12" }
2323
proptest = { optional = true, version = "1" }
24-
proptest-derive = { optional = true, version = "0.3.0" }
24+
proptest-derive = { optional = true, version = "0.4.0" }
2525
rand = { version = "0.8" }
2626
serde = { features = [ "derive" ], version = "1" }
2727
serde_json = { features = [ "float_roundtrip", "preserve_order" ], version = "1" }
@@ -34,14 +34,14 @@ uuid = { features = [ "serde", "v4" ], version = "1.4" }
3434

3535
[dev-dependencies]
3636
colored = { version = "2" }
37-
convex_sync_types = { path = "./sync_types", version = "=0.4.0", features = [ "testing" ] }
37+
convex_sync_types = { path = "./sync_types", version = "=0.5.0", features = [ "testing" ] }
3838
dotenvy = { version = "0.15.7" }
3939
maplit = { version = "1" }
4040
parking_lot = { version = "0.12" }
4141
pretty_assertions = { version = "1" }
4242
proptest = { version = "1" }
43-
proptest-derive = { version = "0.3.0" }
44-
tracing-subscriber = { features = [ "env-filter" ], version = "0.3" }
43+
proptest-derive = { version = "0.4.0" }
44+
tracing-subscriber = { features = [ "env-filter" ], version = "0.3.17" }
4545

4646
[features]
4747
default = [ "native-tls" ]

src/base_client/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,8 @@ impl RemoteQuerySet {
301301
error_message,
302302
log_lines: _,
303303
journal: _,
304+
// TODO @srb: Implement ConvexError in Rust client queries
305+
error_data: _,
304306
} => {
305307
self.remote_query_set
306308
.insert(query_id, FunctionResult::ErrorMessage(error_message));

src/base_client/query_result.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use convex_sync_types::QueryId;
1+
use convex_sync_types::{
2+
types::ErrorPayload,
3+
QueryId,
4+
};
25
use imbl::{
36
OrdMap,
47
OrdSet,
@@ -19,20 +22,22 @@ pub enum FunctionResult {
1922
ErrorMessage(String),
2023
}
2124

22-
impl From<Result<Value, String>> for FunctionResult {
23-
fn from(result: Result<Value, String>) -> Self {
25+
impl From<Result<Value, ErrorPayload<Value>>> for FunctionResult {
26+
fn from(result: Result<Value, ErrorPayload<Value>>) -> Self {
2427
match result {
2528
Ok(value) => FunctionResult::Value(value),
26-
Err(error) => FunctionResult::ErrorMessage(error),
29+
// TODO @srb: Implement ConvexError in Rust client
30+
Err(error) => FunctionResult::ErrorMessage(error.get_message().to_owned()),
2731
}
2832
}
2933
}
3034

31-
impl From<FunctionResult> for Result<Value, String> {
35+
impl From<FunctionResult> for Result<Value, ErrorPayload<Value>> {
3236
fn from(result: FunctionResult) -> Self {
3337
match result {
3438
FunctionResult::Value(value) => Ok(value),
35-
FunctionResult::ErrorMessage(error) => Err(error),
39+
// TODO @srb: Implement ConvexError in Rust client
40+
FunctionResult::ErrorMessage(error) => Err(ErrorPayload::Message(error)),
3641
}
3742
}
3843
}

src/value/export/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use crate::Value;
99
pub mod roundtrip;
1010

1111
impl Value {
12-
/// Converts this value to a JSON value that is more convenient to work with
13-
/// than the internal representation.
12+
/// Converts this value to a JSON value in the `json` export format.
13+
/// <https://docs.convex.dev/database/types>
1414
///
1515
/// It is possible for distinct Convex values to be serialized to the same
1616
/// JSON value by this method. For instance, strings and binary values are

sync_types/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "convex_sync_types"
33
description = "Sync types for the Convex Websocket protocol (convex.dev)"
4-
version = "0.4.0"
4+
version = "0.5.0"
55
authors = [ "Convex, Inc. <team@convex.dev>" ]
66
edition = "2021"
77
rust-version = "1.65.0"
@@ -15,15 +15,15 @@ anyhow = { version = "1" }
1515
base64 = { version = "0.13" }
1616
derive_more = { version = "0.99" }
1717
proptest = { optional = true, version = "1" }
18-
proptest-derive = { optional = true, version = "0.3.0" }
18+
proptest-derive = { optional = true, version = "0.4.0" }
1919
rand = { version = "0.8" }
2020
serde = { features = [ "derive" ], version = "1" }
2121
serde_json = { features = [ "float_roundtrip", "preserve_order" ], version = "1" }
2222
uuid = { features = [ "serde", "v4" ], version = "1.4" }
2323

2424
[dev-dependencies]
2525
proptest = { version = "1" }
26-
proptest-derive = { version = "0.3.0" }
26+
proptest-derive = { version = "0.4.0" }
2727

2828
[features]
2929
testing = [ "proptest", "proptest-derive" ]

sync_types/src/identifier.rs

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use anyhow::bail;
2-
31
pub const MAX_IDENTIFIER_LEN: usize = 64;
42

53
pub const IDENTIFIER_REQUIREMENTS: &str =
@@ -24,33 +22,45 @@ pub const IDENTIFIER_REQUIREMENTS: &str =
2422
/// [3]: <https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=%5B%3AXID_START%3A%5D&g=&i=>
2523
/// [4]: <https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=%5B%3AXID_CONTINUE%3A%5D&g=&i=>
2624
pub fn check_valid_identifier(s: &str) -> anyhow::Result<()> {
25+
check_valid_identifier_inner(s).map_err(|e| anyhow::anyhow!(e))
26+
}
27+
28+
pub fn is_valid_identifier(s: &str) -> bool {
29+
check_valid_identifier_inner(s).is_ok()
30+
}
31+
32+
fn check_valid_identifier_inner(s: &str) -> Result<(), String> {
2733
let mut chars = s.chars();
2834
match chars.next() {
2935
Some(c) if c.is_ascii_alphabetic() => (),
3036
Some('_') => (),
31-
Some(c) => bail!(
32-
"Invalid first character '{c}' in {s}: Identifiers must start with an alphabetic \
33-
character or underscore"
34-
),
35-
None => bail!("Identifier cannot be empty"),
37+
Some(c) => {
38+
return Err(format!(
39+
"Invalid first character '{c}' in {s}: Identifiers must start with an alphabetic \
40+
character or underscore"
41+
))
42+
},
43+
None => return Err(format!("Identifier cannot be empty")),
3644
};
3745
for c in chars {
3846
if !c.is_ascii_alphanumeric() && c != '_' {
39-
bail!(
47+
return Err(format!(
4048
"Identifier {s} has invalid character '{c}': Identifiers can only contain \
4149
alphanumeric characters or underscores"
42-
);
50+
));
4351
}
4452
}
4553
if s.len() > MAX_IDENTIFIER_LEN {
46-
bail!(
54+
return Err(format!(
4755
"Identifier is too long ({} > maximum {})",
4856
s.len(),
4957
MAX_IDENTIFIER_LEN
50-
);
58+
));
5159
}
5260
if s.chars().all(|c| c == '_') {
53-
bail!("Identifier {s} cannot have exclusively underscores");
61+
return Err(format!(
62+
"Identifier {s} cannot have exclusively underscores"
63+
));
5464
}
5565
Ok(())
5666
}
@@ -64,33 +74,45 @@ pub const MAX_FIELD_NAME_LENGTH: usize = 1024;
6474
/// Field names cannot start with '$', must contain only non-control ASCII
6575
/// characters, and must be at most 1024 characters long.
6676
pub fn check_valid_field_name(s: &str) -> anyhow::Result<()> {
77+
check_valid_field_name_inner(s).map_err(|e| anyhow::anyhow!(e))
78+
}
79+
80+
pub fn is_valid_field_name(s: &str) -> bool {
81+
check_valid_field_name_inner(s).is_ok()
82+
}
83+
84+
fn check_valid_field_name_inner(s: &str) -> Result<(), String> {
6785
let mut chars = s.chars();
6886
match chars.next() {
69-
Some('$') => bail!("Field name {s} starts with '$', which is reserved."),
87+
Some('$') => {
88+
return Err(format!(
89+
"Field name {s} starts with '$', which is reserved."
90+
))
91+
},
7092
Some(c) => {
7193
if !c.is_ascii() || c.is_ascii_control() {
72-
bail!(
94+
return Err(format!(
7395
"Field name {s} has invalid character '{c}': Field names can only contain \
7496
non-control ASCII characters"
75-
);
97+
));
7698
}
7799
},
78-
None => bail!("Field name cannot be empty"),
100+
None => return Err(format!("Field name cannot be empty")),
79101
};
80102
for c in chars {
81103
if !c.is_ascii() || c.is_ascii_control() {
82-
bail!(
104+
return Err(format!(
83105
"Field name {s} has invalid character '{c}': Field names can only contain \
84106
non-control ASCII characters"
85-
);
107+
));
86108
}
87109
}
88110
if s.len() > MAX_FIELD_NAME_LENGTH {
89-
bail!(
111+
return Err(format!(
90112
"Field name is too long ({} > maximum {})",
91113
s.len(),
92114
MAX_FIELD_NAME_LENGTH
93-
);
115+
));
94116
}
95117
Ok(())
96118
}

0 commit comments

Comments
 (0)