pgevolve_core/diff/
reloptions.rs1use crate::ir::reloptions::{AutovacuumOptions, IndexStorageOptions, TableStorageOptions};
6
7#[must_use]
13pub fn table_delta(
14 target: &TableStorageOptions,
15 source: &TableStorageOptions,
16) -> TableStorageOptions {
17 let mut out = TableStorageOptions::default();
18
19 macro_rules! diff_field {
20 ($field:ident) => {
21 if let Some(src) = &source.$field {
22 if target.$field.as_ref() != Some(src) {
23 out.$field = Some(src.clone());
24 }
25 }
26 };
27 }
28
29 diff_field!(fillfactor);
30 diff_field!(parallel_workers);
31 diff_field!(toast_tuple_target);
32 diff_field!(user_catalog_table);
33 diff_field!(vacuum_truncate);
34
35 out.autovacuum = autovacuum_delta(&target.autovacuum, &source.autovacuum);
36
37 for (k, src_v) in &source.extra {
39 if target.extra.get(k) != Some(src_v) {
40 out.extra.insert(k.clone(), src_v.clone());
41 }
42 }
43
44 out
45}
46
47#[must_use]
51pub fn index_delta(
52 target: &IndexStorageOptions,
53 source: &IndexStorageOptions,
54) -> IndexStorageOptions {
55 let mut out = IndexStorageOptions::default();
56
57 macro_rules! diff_field {
58 ($field:ident) => {
59 if let Some(src) = &source.$field {
60 if target.$field.as_ref() != Some(src) {
61 out.$field = Some(src.clone());
62 }
63 }
64 };
65 }
66
67 diff_field!(fillfactor);
68 diff_field!(fastupdate);
69 diff_field!(gin_pending_list_limit);
70 diff_field!(buffering);
71 diff_field!(deduplicate_items);
72 diff_field!(pages_per_range);
73 diff_field!(autosummarize);
74
75 for (k, src_v) in &source.extra {
76 if target.extra.get(k) != Some(src_v) {
77 out.extra.insert(k.clone(), src_v.clone());
78 }
79 }
80
81 out
82}
83
84fn autovacuum_delta(target: &AutovacuumOptions, source: &AutovacuumOptions) -> AutovacuumOptions {
85 let mut out = AutovacuumOptions::default();
86
87 macro_rules! diff_field {
88 ($field:ident) => {
89 if let Some(src) = &source.$field {
90 if target.$field.as_ref() != Some(src) {
91 out.$field = Some(src.clone());
92 }
93 }
94 };
95 }
96
97 diff_field!(enabled);
98 diff_field!(vacuum_threshold);
99 diff_field!(vacuum_scale_factor);
100 diff_field!(vacuum_cost_delay);
101 diff_field!(vacuum_cost_limit);
102 diff_field!(analyze_threshold);
103 diff_field!(analyze_scale_factor);
104 diff_field!(freeze_max_age);
105 diff_field!(freeze_min_age);
106 diff_field!(freeze_table_age);
107 diff_field!(multixact_freeze_max_age);
108 diff_field!(multixact_freeze_min_age);
109 diff_field!(multixact_freeze_table_age);
110 diff_field!(vacuum_insert_threshold);
111 diff_field!(vacuum_insert_scale_factor);
112 diff_field!(log_min_duration);
113
114 out
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 #[test]
122 fn empty_source_yields_empty_delta() {
123 let t = TableStorageOptions {
124 fillfactor: Some(80),
125 ..Default::default()
126 };
127 let s = TableStorageOptions::default();
128 let delta = table_delta(&t, &s);
129 assert!(delta.is_empty(), "lenient: source None means skip");
130 }
131
132 #[test]
133 fn source_only_fillfactor_emits_one_field() {
134 let t = TableStorageOptions::default();
135 let s = TableStorageOptions {
136 fillfactor: Some(80),
137 ..Default::default()
138 };
139 let delta = table_delta(&t, &s);
140 assert_eq!(delta.fillfactor, Some(80));
141 assert!(delta.autovacuum.is_empty());
142 }
143
144 #[test]
145 fn matching_source_and_target_yields_empty_delta() {
146 let t = TableStorageOptions {
147 fillfactor: Some(80),
148 ..Default::default()
149 };
150 let s = TableStorageOptions {
151 fillfactor: Some(80),
152 ..Default::default()
153 };
154 let delta = table_delta(&t, &s);
155 assert!(delta.is_empty());
156 }
157
158 #[test]
159 fn source_extra_key_not_in_target_emits() {
160 let t = TableStorageOptions::default();
161 let mut s = TableStorageOptions::default();
162 s.extra.insert("pg_partman.foo".into(), "value".into());
163 let delta = table_delta(&t, &s);
164 assert_eq!(
165 delta.extra.get("pg_partman.foo").map(String::as_str),
166 Some("value")
167 );
168 }
169
170 #[test]
171 fn target_extra_key_not_in_source_does_not_emit() {
172 let mut t = TableStorageOptions::default();
173 t.extra.insert("pg_partman.foo".into(), "value".into());
174 let s = TableStorageOptions::default();
175 let delta = table_delta(&t, &s);
176 assert!(
177 delta.is_empty(),
178 "lenient: unmanaged extra-bag keys ignored"
179 );
180 }
181
182 #[test]
183 fn index_delta_fillfactor_change() {
184 let t = IndexStorageOptions {
185 fillfactor: Some(70),
186 ..Default::default()
187 };
188 let s = IndexStorageOptions {
189 fillfactor: Some(80),
190 ..Default::default()
191 };
192 let delta = index_delta(&t, &s);
193 assert_eq!(delta.fillfactor, Some(80));
194 }
195}