Skip to content

Commit 35cc452

Browse files
committed
sea-orm-sync example
1 parent 6e68ccd commit 35cc452

File tree

16 files changed

+258
-28
lines changed

16 files changed

+258
-28
lines changed

build-tools/make-sync.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ find src -type f -name '*.rs' -exec sed -i '' 's/S: Stream</S: Iterator</' {} +
4242
find src -type f -name '*.rs' -exec sed -i '' 's/use futures_util::lock::Mutex;/use std::sync::Mutex;/' {} +
4343
find src -type f -name '*.rs' -exec sed -i '' 's/use futures_util::lock::MutexGuard;/use std::sync::MutexGuard;/' {} +
4444
find src -type f -name '*.rs' -exec sed -i '' 's/, pin::Pin//' {} +
45+
find src -type f -name '*.rs' -exec sed -i '' 's/{pin::Pin, /{/' {} +
46+
find src -type f -name '*.rs' -exec sed -i '' 's/{task::Poll, /{/' {} +
47+
find src -type f -name '*.rs' -exec sed -i '' 's/{future::Future, /{/' {} +
48+
find src -type f -name '*.rs' -exec sed -i '' 's/, task::Poll//' {} +
49+
find src -type f -name '*.rs' -exec sed -i '' '/use std::{pin::Pin};/d' {} +
50+
find src -type f -name '*.rs' -exec sed -i '' '/use std::{task::Poll};/d' {} +
51+
find src -type f -name '*.rs' -exec sed -i '' '/use std::{future::Future};/d' {} +
4552
find src -type f -name '*.rs' -exec sed -i '' 's/, future::Future//' {} +
4653
find src -type f -name '*.rs' -exec sed -i '' '/use futures_util::Stream/d' {} +
4754
find src -type f -name '*.rs' -exec sed -i '' '/use futures_util::{Stream/d' {} +

sea-orm-sync/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[workspace]
2-
members = [".", "examples/quickstart"]
2+
members = [".", "examples/quickstart", "examples/pi_spigot"]
33

44
[package]
55
authors = ["Chris Tsang <[email protected]>"]
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[package]
2+
edition = "2024"
3+
name = "sea-orm-pi-spigot"
4+
publish = false
5+
rust-version = "1.85.0"
6+
version = "0.1.0"
7+
8+
[dependencies]
9+
serde = { version = "1", features = ["derive"] }
10+
serde_json = { version = "1" }
11+
12+
[dependencies.sea-orm-sync]
13+
features = ["rusqlite", "with-json", "schema-sync"]
14+
path = "../../"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Pi Spigot Algorithm
2+
3+
This program implements the Rabinowitz-Wagon decimal spigot algorithm to generate
4+
1 million digits of pi without big integer libraries.
5+
6+
It shows how to easily use SeaORM to a program to make it resumable and persistent.
7+
Run the program, press Ctrl-C at any time to pause, and run it again.
8+
Instead of restarting from beginning, it will continue from exactly where it left off.
9+
It also saves the pi digits to a SQLite table.
10+
11+
This is definitely not the fastest pi computation algorithm, but the simplicity and
12+
streaming nature makes it the best for demonstrating a long running process.
15.9 MB
Binary file not shown.
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
use std::io::Write as _;
2+
3+
/// SeaORM Entity for state persistence
4+
mod state {
5+
use sea_orm::entity::prelude::*;
6+
use serde::{Deserialize, Serialize};
7+
8+
#[sea_orm::model]
9+
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
10+
#[sea_orm(table_name = "state")]
11+
pub struct Model {
12+
#[sea_orm(primary_key, auto_increment = false)]
13+
pub digits: u32,
14+
pub boxes: Digits,
15+
pub i: u32,
16+
pub nines: u32,
17+
pub predigit: u8,
18+
pub have_predigit: bool,
19+
pub count: u32,
20+
}
21+
22+
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, FromJsonQueryResult)]
23+
pub struct Digits(pub Vec<u32>);
24+
25+
impl ActiveModelBehavior for ActiveModel {}
26+
}
27+
28+
mod run_log {
29+
use sea_orm::entity::prelude::*;
30+
use serde::{Deserialize, Serialize};
31+
32+
#[sea_orm::model]
33+
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
34+
#[sea_orm(table_name = "run_log")]
35+
pub struct Model {
36+
#[sea_orm(primary_key)]
37+
pub id: i32,
38+
pub digits: u32,
39+
pub pi_digits: String,
40+
}
41+
42+
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, FromJsonQueryResult)]
43+
pub struct Digits(pub Vec<u32>);
44+
45+
impl ActiveModelBehavior for ActiveModel {}
46+
}
47+
48+
fn pi_spigot(digits: u32) {
49+
use sea_orm::{ActiveModelTrait, EntityTrait, IntoActiveModel, NotSet, Set, TransactionTrait};
50+
51+
// open database file, create if not exists
52+
let db = &sea_orm::Database::connect("sqlite://pi.sqlite").unwrap();
53+
db.get_schema_builder()
54+
.register(state::Entity)
55+
.register(run_log::Entity)
56+
.sync(db) // create table if not exists
57+
.unwrap();
58+
59+
if digits == 0 {
60+
println!("3");
61+
return;
62+
}
63+
64+
let len = digits as usize * 10 / 3 + 1;
65+
66+
let state = match state::Entity::find_by_id(digits).one(db).unwrap() {
67+
Some(state) => {
68+
println!("resuming from {}th digit", state.count);
69+
state
70+
}
71+
None => state::Model {
72+
digits,
73+
boxes: state::Digits(vec![2u32; len]),
74+
i: 0,
75+
nines: 0,
76+
predigit: 0,
77+
have_predigit: false,
78+
count: 0,
79+
}
80+
.into_active_model()
81+
.insert(db)
82+
.unwrap(),
83+
};
84+
let mut run_log = run_log::ActiveModel {
85+
id: NotSet,
86+
digits: Set(digits),
87+
pi_digits: Set("".to_owned()),
88+
}
89+
.save(db)
90+
.unwrap();
91+
92+
let mut boxes = state.boxes.0;
93+
let mut nines = state.nines;
94+
let mut predigit = state.predigit;
95+
let mut have_predigit = state.have_predigit;
96+
let mut count = state.count;
97+
let mut s = String::new();
98+
99+
for i in (0..(digits + 1)).skip(state.i as usize) {
100+
if count % 100 == 0 {
101+
std::io::stdout().flush().unwrap();
102+
// save checkpoint
103+
let txn = db.begin().unwrap();
104+
state::Model {
105+
digits,
106+
boxes: state::Digits(boxes.clone()),
107+
i,
108+
nines: nines,
109+
predigit: predigit,
110+
have_predigit: have_predigit,
111+
count: count,
112+
}
113+
.into_active_model()
114+
.reset_all() // we want to update all fields
115+
.update(&txn)
116+
.unwrap();
117+
118+
run_log.pi_digits = Set(s.to_owned());
119+
run_log = run_log.save(&txn).unwrap();
120+
121+
txn.commit().unwrap();
122+
}
123+
124+
let mut carry: u32 = 0;
125+
// work backwards over boxes 1..len-1
126+
for j in (1..len).rev() {
127+
let j_u = j as u32;
128+
let x = boxes[j] * 10 + carry;
129+
let q = x / (2 * j_u + 1);
130+
boxes[j] = x % (2 * j_u + 1);
131+
carry = q * j_u;
132+
}
133+
let x = boxes[0] * 10 + carry;
134+
let q = (x / 10) as u8; // 0..10
135+
boxes[0] = x % 10;
136+
137+
if q == 9 {
138+
nines += 1;
139+
} else if q == 10 {
140+
// increment previous printed digit
141+
if have_predigit {
142+
new_digit(&mut s, predigit + 1);
143+
count += 1;
144+
} else {
145+
// first digit becomes 1
146+
new_digit(&mut s, 1);
147+
count += 1;
148+
have_predigit = true;
149+
}
150+
for _ in 0..nines {
151+
new_digit(&mut s, 0);
152+
count += 1;
153+
}
154+
predigit = 0;
155+
nines = 0;
156+
} else {
157+
if have_predigit {
158+
new_digit(&mut s, predigit);
159+
count += 1;
160+
if count == 1 {
161+
println!(".");
162+
}
163+
} else {
164+
have_predigit = true;
165+
}
166+
predigit = q;
167+
for _ in 0..nines {
168+
new_digit(&mut s, 9);
169+
count += 1;
170+
}
171+
nines = 0;
172+
}
173+
}
174+
175+
// append last predigit
176+
new_digit(&mut s, predigit);
177+
178+
println!();
179+
run_log.pi_digits = Set(s.to_owned());
180+
run_log.save(db).unwrap();
181+
}
182+
183+
fn new_digit(s: &mut String, digit: u8) {
184+
let c = (b'0' + digit) as char;
185+
s.push(c);
186+
print!("{c}");
187+
}
188+
189+
fn main() {
190+
pi_spigot(1_000_000);
191+
}

sea-orm-sync/src/database/connection.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use crate::{
22
DbBackend, DbErr, ExecResult, QueryResult, Statement, StatementBuilder, TransactionError,
33
};
4-
use std::future::Future;
54

65
/// The generic API for a database connection that can perform query or execute statements.
76
/// It abstracts database connection and transaction

sea-orm-sync/src/database/stream/metric.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{pin::Pin, task::Poll, time::Duration};
1+
use std::time::Duration;
22

33
use crate::{DbErr, QueryResult, Statement};
44

sea-orm-sync/src/database/stream/query.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#![allow(missing_docs, unreachable_code, unused_variables)]
22

3-
use std::{pin::Pin, task::Poll};
43
use tracing::instrument;
54

65
#[cfg(feature = "sqlx-dep")]

sea-orm-sync/src/database/stream/transaction.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![allow(missing_docs)]
22

3-
use std::{ops::DerefMut, task::Poll};
3+
use std::ops::DerefMut;
44
use tracing::instrument;
55

66
#[cfg(feature = "sqlx-dep")]

0 commit comments

Comments
 (0)