Skip to content

Commit c949e60

Browse files
committed
fix migration primary key generator state bug
1 parent de2157f commit c949e60

4 files changed

Lines changed: 132 additions & 3 deletions

File tree

codegen/src/generators/persist/table/impls.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ impl PersistGenerator {
2020
let reinsert_fn = self.gen_table_reinsert_fn();
2121
let upsert_fn = self.gen_table_upsert_fn();
2222
let get_next_fn = self.gen_table_get_next_fn();
23+
let pk_gen_state_fn = self.gen_table_pk_gen_state_fn();
2324
let iter_with_fn = self.gen_table_iter_with_fn();
2425
let iter_with_async_fn = self.gen_table_iter_with_async_fn();
2526
let count_fn = self.gen_table_count_fn();
@@ -38,6 +39,7 @@ impl PersistGenerator {
3839
#upsert_fn
3940
#count_fn
4041
#get_next_fn
42+
#pk_gen_state_fn
4143
#iter_with_fn
4244
#iter_with_async_fn
4345
#system_info_fn
@@ -279,6 +281,17 @@ impl PersistGenerator {
279281
}
280282
}
281283

284+
fn gen_table_pk_gen_state_fn(&self) -> TokenStream {
285+
let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string());
286+
let primary_key_type = name_generator.get_primary_key_type_ident();
287+
288+
quote! {
289+
pub fn pk_gen_state(&self) -> <<#primary_key_type as TablePrimaryKey>::Generator as PrimaryKeyGeneratorState>::State {
290+
self.0.pk_gen.get_state()
291+
}
292+
}
293+
}
294+
282295
fn gen_table_iter_with_fn(&self) -> TokenStream {
283296
let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string());
284297
let row_type = name_generator.get_row_type_ident();

codegen/src/generators/read_only/table/impls.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ impl ReadOnlyGenerator {
1919
let reinsert_fn = self.gen_table_reinsert_fn();
2020
let upsert_fn = self.gen_table_upsert_fn();
2121
let get_next_fn = self.gen_table_get_next_fn();
22+
let pk_gen_state_fn = self.gen_table_pk_gen_state_fn();
2223
let iter_with_fn = self.gen_table_iter_with_fn();
2324
let iter_with_async_fn = self.gen_table_iter_with_async_fn();
2425
let count_fn = self.gen_table_count_fn();
@@ -37,6 +38,7 @@ impl ReadOnlyGenerator {
3738
#upsert_fn
3839
#count_fn
3940
#get_next_fn
41+
#pk_gen_state_fn
4042
#iter_with_fn
4143
#iter_with_async_fn
4244
#system_info_fn
@@ -229,6 +231,17 @@ impl ReadOnlyGenerator {
229231
}
230232
}
231233

234+
fn gen_table_pk_gen_state_fn(&self) -> TokenStream {
235+
let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string());
236+
let primary_key_type = name_generator.get_primary_key_type_ident();
237+
238+
quote! {
239+
pub fn pk_gen_state(&self) -> <<#primary_key_type as TablePrimaryKey>::Generator as PrimaryKeyGeneratorState>::State {
240+
self.0.pk_gen.get_state()
241+
}
242+
}
243+
}
244+
232245
fn gen_table_iter_with_fn(&self) -> TokenStream {
233246
let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string());
234247
let row_type = name_generator.get_row_type_ident();

codegen/src/migration_engine/generator.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,13 @@ pub fn generate(input: MigrationEngineInput) -> TokenStream {
3636
quote! {
3737
async fn #fn_name(
3838
source_path: &str,
39-
target: &#current_table,
39+
target: &mut #current_table,
4040
ctx: &#ctx_type,
4141
) -> eyre::Result<()> {
4242
let config = DiskConfig::new_with_table_name(source_path, #table_name_lit, #version);
4343
let engine = ReadOnlyPersistenceEngine::create(config).await?;
4444
let source = #table_path::load(engine).await?;
45+
target.0.pk_gen = worktable::prelude::PrimaryKeyGeneratorState::from_state(source.pk_gen_state());
4546

4647
let rows = source.select_all().execute()?;
4748
for row in rows {
@@ -57,7 +58,7 @@ pub fn generate(input: MigrationEngineInput) -> TokenStream {
5758
let match_arms = input.version_tables.keys().map(|version| {
5859
let fn_name = Ident::new(&format!("migrate_v{}", version), current_table.span());
5960
quote! {
60-
#version => Self::#fn_name(source_path, &target, ctx).await?,
61+
#version => Self::#fn_name(source_path, &mut target, ctx).await?,
6162
}
6263
});
6364

@@ -77,7 +78,7 @@ pub fn generate(input: MigrationEngineInput) -> TokenStream {
7778

7879
let target_config = DiskConfig::new_with_table_name(target_path, #table_name_lit, #current_version);
7980
let target_engine = #persistence_engine::new(target_config).await?;
80-
let target = #current_table::new(target_engine).await?;
81+
let mut target = #current_table::new(target_engine).await?;
8182

8283
match version {
8384
#( #match_arms )*

tests/migration/mod.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,108 @@ fn test_migrate_v2_to_current() {
242242
});
243243
}
244244

245+
#[test]
246+
fn test_next_pk_and_indexes_after_migration() {
247+
let runtime = tokio::runtime::Builder::new_multi_thread()
248+
.worker_threads(2)
249+
.enable_io()
250+
.enable_time()
251+
.build()
252+
.unwrap();
253+
254+
runtime.block_on(async {
255+
let src = "tests/data/migration/next_pk_after_migration";
256+
let dst = "tests/data/migration/next_pk_after_migration/dst";
257+
remove_dir_if_exists(src.to_string()).await;
258+
259+
{
260+
let config = DiskConfig::new_with_table_name(
261+
src,
262+
v2::UserWorkTable::name_snake_case(),
263+
v2::UserWorkTable::version(),
264+
);
265+
let engine = v2::UserPersistenceEngine::new(config).await.unwrap();
266+
let table = v2::UserWorkTable::load(engine).await.unwrap();
267+
268+
table
269+
.insert(v2::UserRow {
270+
id: table.get_next_pk().into(),
271+
name: "Eve".to_string(),
272+
email: "eve@test.com".to_string(),
273+
})
274+
.unwrap();
275+
table
276+
.insert(v2::UserRow {
277+
id: table.get_next_pk().into(),
278+
name: "Frank".to_string(),
279+
email: "frank@test.com".to_string(),
280+
})
281+
.unwrap();
282+
283+
table.wait_for_ops().await;
284+
}
285+
286+
let ctx = UserMigrationContext {
287+
default_email: "unknown@example.com".to_string(),
288+
default_created_at: chrono::Utc::now().timestamp() as u64,
289+
};
290+
291+
let report = UserMigrationEngine::migrate(src, dst, &ctx).await.unwrap();
292+
assert_eq!(report.source_version, v2::UserWorkTable::version());
293+
294+
let inserted = {
295+
let config =
296+
DiskConfig::new_with_table_name(dst, UserWorkTable::name_snake_case(), UserWorkTable::version());
297+
let engine = UserPersistenceEngine::new(config).await.unwrap();
298+
let table = UserWorkTable::load(engine).await.unwrap();
299+
300+
let next_pk = table.get_next_pk();
301+
assert_eq!(next_pk, 2_u64.into());
302+
303+
let inserted = UserRow {
304+
id: next_pk.into(),
305+
name: "Grace".to_string(),
306+
email: "grace@test.com".to_string(),
307+
created_at: ctx.default_created_at + 1,
308+
};
309+
310+
table.insert(inserted.clone()).unwrap();
311+
table.wait_for_ops().await;
312+
313+
assert_eq!(table.count(), 3);
314+
assert_eq!(table.select(inserted.id), Some(inserted.clone()));
315+
316+
let by_name = table.select_by_name(inserted.name.clone()).execute().unwrap();
317+
assert_eq!(by_name, vec![inserted.clone()]);
318+
319+
let by_name_range = table
320+
.select_by_name_range(inserted.name.clone()..=inserted.name.clone())
321+
.execute()
322+
.unwrap();
323+
assert_eq!(by_name_range, vec![inserted.clone()]);
324+
325+
let by_pk_range = table.select_by_pk_range(inserted.id..=inserted.id).execute().unwrap();
326+
assert_eq!(by_pk_range, vec![inserted.clone()]);
327+
328+
inserted
329+
};
330+
331+
{
332+
let config =
333+
DiskConfig::new_with_table_name(dst, UserWorkTable::name_snake_case(), UserWorkTable::version());
334+
let engine = UserPersistenceEngine::new(config).await.unwrap();
335+
let table = UserWorkTable::load(engine).await.unwrap();
336+
337+
assert_eq!(table.count(), 3);
338+
assert_eq!(table.select(inserted.id), Some(inserted.clone()));
339+
assert_eq!(
340+
table.select_by_name(inserted.name.clone()).execute().unwrap(),
341+
vec![inserted.clone()]
342+
);
343+
}
344+
});
345+
}
346+
245347
/// Nonexistent source returns an error
246348
#[test]
247349
fn test_nonexistent_source_error() {

0 commit comments

Comments
 (0)