Skip to content

Commit 8683b2a

Browse files
committed
update
1 parent 1e2634f commit 8683b2a

File tree

3 files changed

+115
-4
lines changed

3 files changed

+115
-4
lines changed

examples/surrealdb/cli-multi-counter/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ async fn main() -> surrealdb::Result<()> {
3434
eprintln!(" {} to list all the counters", args[0]);
3535
std::process::exit(1);
3636
}
37-
37+
3838
if 2 == args.len() {
3939
let name = &args[1];
4040
let mut count = 0;

examples/surrealdb/cli-multi-counter/tests/tests.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,15 @@ fn test_counter() {
3434
}
3535

3636
fn check(name: &str, expected_stdout: &str) {
37-
3837
let result = Command::new("cargo")
3938
.args(["run", "-q", name])
4039
.output()
4140
.expect("command failed to start");
4241

43-
assert_eq!(std::str::from_utf8(&result.stdout).unwrap(), expected_stdout);
42+
assert_eq!(
43+
std::str::from_utf8(&result.stdout).unwrap(),
44+
expected_stdout
45+
);
4446
assert_eq!(std::str::from_utf8(&result.stderr).unwrap(), "");
4547
assert_eq!(result.status, ExitStatus::from_raw(0));
4648
}
47-

pages/surrealdb-cli-multi-counter.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,116 @@ SurrealDB can use various storage backends, we are going to us [RocksDB](https:/
3939
4040
![](examples/surrealdb/cli-multi-counter/Cargo.toml)
4141
42+
## The code
43+
44+
### Getting the command line from args
45+
46+
This has nothing to do with SurrealDB yet. We only create a vector from the values on the command line:
47+
48+
49+
```rust
50+
let args = std::env::args().collect::<Vec<String>>();
51+
```
52+
53+
### Getting the path to the database
54+
55+
We check the `DATABASE_PATH` enviroment variabl and use that if it is available. This will be used by the tests to be able to use
56+
a database in a temporary folder.
57+
58+
If that variable is not available then we are going to create the database in the `db` folder in the current directory.
59+
60+
I did not use the plain `db` because of a [bug](https://github.com/surrealdb/docs.surrealdb.com/issues/185) that was fixed recently.
61+
62+
I also used [unwrap](/unwrap) disregarding the possibiliy that we don't have a current working directory. For a more robust solution
63+
you might want to deal with that as well.
64+
65+
```rust
66+
let database_folder = match std::env::var("DATABASE_PATH") {
67+
Ok(val) => std::path::PathBuf::from(val),
68+
Err(_) => {
69+
let current_dir = std::env::current_dir().unwrap();
70+
current_dir.join("db")
71+
}
72+
};
73+
```
74+
75+
### Connect to the database on the filesystem
76+
77+
Then we connect to the databse folder via the `RocksDb` driver.
78+
79+
```rust
80+
let db = Surreal::new::<RocksDb>(database_folder).await?;
81+
```
82+
83+
### Namespace and database
84+
85+
Each SurrealDB installation can handle multiple namespaces and multiple databases in each namespace. We just need to pick one for each:
86+
87+
```rust
88+
db.use_ns("counter_ns").use_db("counter_db").await?;
89+
```
90+
91+
### Make column unique
92+
93+
Let's make sure we don't add the same counter name twice.
94+
95+
```rust
96+
let _response = db
97+
.query("DEFINE INDEX counter_name ON TABLE counter COLUMNS name UNIQUE")
98+
.await?;
99+
```
100+
101+
### Too many arguments
102+
103+
Tell the user how to use the tool if there is more than one value on the command line. (args includes the name of the executable file so we need to compare with 2 here).
104+
105+
```rust
106+
if 2 < args.len() {
107+
eprintln!("Usage: {} NAME to count NAME", args[0]);
108+
eprintln!(" {} to list all the counters", args[0]);
109+
std::process::exit(1);
110+
}
111+
```
112+
113+
### Increment the counter
114+
115+
I guess this is the heart of the progam where we fetch the current value of the counter using a `SELECT` statement and then
116+
update the value in the database. We use `INSERT` here as it can either `CREATE` a new record or `UPDATE` and existing one.
117+
118+
```rust
119+
if 2 == args.len() {
120+
let name = &args[1];
121+
let mut count = 0;
122+
123+
let mut entries = db
124+
.query("SELECT name, count FROM counter WHERE name = $name")
125+
.bind(("name", name))
126+
.await?;
127+
let entries: Vec<Entry> = entries.take(0)?;
128+
if let Some(entry) = entries.into_iter().next() {
129+
count = entry.count;
130+
}
131+
132+
count += 1;
133+
println!("{}", count);
134+
135+
let response = db
136+
.query("INSERT INTO counter (name, count) VALUES ($name, $count) ON DUPLICATE KEY UPDATE count=$count")
137+
.bind(("name", name))
138+
.bind(("count", count))
139+
.await?;
140+
141+
match response.check() {
142+
Ok(_) => return Ok(()),
143+
Err(err) => {
144+
eprintln!("Could not add entry {}", err);
145+
std::process::exit(2);
146+
}
147+
};
148+
}
149+
```
150+
151+
42152

43153
## The full code
44154

0 commit comments

Comments
 (0)