Skip to content

Commit 51170dc

Browse files
feat(template): support for steppable templates (#818)
1 parent 98f638c commit 51170dc

11 files changed

Lines changed: 649 additions & 156 deletions

File tree

CLAUDE.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,9 +296,14 @@ Templates are **reusable, declarative change definitions** that enable "no-code
296296
- `ROLLBACK_FIELD` - Payload type for the rollback operation
297297

298298
**Base Class**: `AbstractChangeTemplate` resolves generic types via reflection and provides:
299-
- Field management: `changeId`, `isTransactional`, `configuration`, `applyPayload`, `rollbackPayload`
299+
- Field management: `changeId`, `isTransactional`, `configuration`
300+
- Generic type resolution for APPLY and ROLLBACK payload classes
300301
- Reflective class collection for GraalVM native image support
301302

303+
**Specialized Classes**:
304+
- `AbstractSimpleTemplate`: For single-step changes with `setStep()`/`getStep()`
305+
- `AbstractSteppableTemplate`: For multi-step changes with `setSteps()`/`getSteps()`
306+
302307
**Key Files**:
303308
- `core/flamingock-core-api/src/main/java/io/flamingock/api/template/ChangeTemplate.java`
304309
- `core/flamingock-core-api/src/main/java/io/flamingock/api/template/AbstractChangeTemplate.java`

core/flamingock-core-api/src/main/java/io/flamingock/api/template/AbstractChangeTemplate.java

Lines changed: 12 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,21 @@
2020
import java.util.Arrays;
2121
import java.util.Collection;
2222
import java.util.HashSet;
23-
import java.util.List;
2423
import java.util.Set;
2524

2625

26+
/**
27+
* Abstract base class for change templates providing common functionality.
28+
*
29+
* <p>This class handles generic type resolution and provides the common fields
30+
* needed by all templates: changeId, isTransactional, and configuration.
31+
*
32+
* <p>For new templates, extend one of the specialized abstract classes:
33+
* <ul>
34+
* <li>{@link AbstractSimpleTemplate} - for templates with a single apply/rollback step</li>
35+
* <li>{@link AbstractSteppableTemplate} - for templates with multiple steps</li>
36+
* </ul>
37+
*/
2738
public abstract class AbstractChangeTemplate<SHARED_CONFIGURATION_FIELD, APPLY_FIELD, ROLLBACK_FIELD> implements ChangeTemplate<SHARED_CONFIGURATION_FIELD, APPLY_FIELD, ROLLBACK_FIELD> {
2839

2940
private final Class<SHARED_CONFIGURATION_FIELD> configurationClass;
@@ -32,18 +43,6 @@ public abstract class AbstractChangeTemplate<SHARED_CONFIGURATION_FIELD, APPLY_F
3243
protected String changeId;
3344
protected boolean isTransactional;
3445
protected SHARED_CONFIGURATION_FIELD configuration;
35-
/**
36-
* @deprecated Use {@link #stepsPayload} instead. Will be removed in a future release.
37-
*/
38-
@Deprecated
39-
protected APPLY_FIELD applyPayload;
40-
/**
41-
* @deprecated Use {@link #stepsPayload} instead. Will be removed in a future release.
42-
*/
43-
@Deprecated
44-
protected ROLLBACK_FIELD rollbackPayload;
45-
protected List<TemplateStep<APPLY_FIELD, ROLLBACK_FIELD>> stepsPayload;
46-
4746

4847
private final Set<Class<?>> reflectiveClasses;
4948

@@ -94,34 +93,6 @@ public void setConfiguration(SHARED_CONFIGURATION_FIELD configuration) {
9493
this.configuration = configuration;
9594
}
9695

97-
/**
98-
* @deprecated Use {@link #setStepsPayload(List)} instead. Will be removed in a future release.
99-
*/
100-
@Deprecated
101-
@Override
102-
public void setApplyPayload(APPLY_FIELD applyPayload) {
103-
this.applyPayload = applyPayload;
104-
}
105-
106-
/**
107-
* @deprecated Use {@link #setStepsPayload(List)} instead. Will be removed in a future release.
108-
*/
109-
@Deprecated
110-
@Override
111-
public void setRollbackPayload(ROLLBACK_FIELD rollbackPayload) {
112-
this.rollbackPayload = rollbackPayload;
113-
}
114-
115-
@Override
116-
public void setStepsPayload(List<TemplateStep<APPLY_FIELD, ROLLBACK_FIELD>> stepsPayload) {
117-
this.stepsPayload = stepsPayload;
118-
}
119-
120-
@Override
121-
public List<TemplateStep<APPLY_FIELD, ROLLBACK_FIELD>> getStepsPayload() {
122-
return stepsPayload;
123-
}
124-
12596
@Override
12697
public Class<SHARED_CONFIGURATION_FIELD> getConfigurationClass() {
12798
return configurationClass;
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright 2025 Flamingock (https://www.flamingock.io)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.flamingock.api.template;
17+
18+
/**
19+
* Abstract base class for templates with a single apply/rollback step.
20+
*
21+
* <p>Use this class when your template processes a single operation that may have
22+
* an optional rollback. The YAML structure for this template type is:
23+
*
24+
* <pre>{@code
25+
* id: create-users-table
26+
* template: SqlTemplate
27+
* apply: "CREATE TABLE users ..."
28+
* rollback: "DROP TABLE users"
29+
* }</pre>
30+
*
31+
* <p>The framework will automatically create a {@link TemplateStep} from the
32+
* apply/rollback fields in the YAML and inject it via {@link #setStep}.
33+
*
34+
* @param <SHARED_CONFIG> the type of shared configuration
35+
* @param <APPLY> the type of the apply payload
36+
* @param <ROLLBACK> the type of the rollback payload
37+
*/
38+
public abstract class AbstractSimpleTemplate<SHARED_CONFIG, APPLY, ROLLBACK>
39+
extends AbstractChangeTemplate<SHARED_CONFIG, APPLY, ROLLBACK> {
40+
41+
protected TemplateStep<APPLY, ROLLBACK> step;
42+
43+
public AbstractSimpleTemplate(Class<?>... additionalReflectiveClass) {
44+
super(additionalReflectiveClass);
45+
}
46+
47+
/**
48+
* Sets the step containing the apply and optional rollback payloads.
49+
*
50+
* @param step the template step
51+
*/
52+
public void setStep(TemplateStep<APPLY, ROLLBACK> step) {
53+
this.step = step;
54+
}
55+
56+
/**
57+
* Returns the step containing the apply and optional rollback payloads.
58+
*
59+
* @return the template step, or null if not set
60+
*/
61+
public TemplateStep<APPLY, ROLLBACK> getStep() {
62+
return step;
63+
}
64+
65+
/**
66+
* Checks if this template has a step set.
67+
*
68+
* @return true if a step is set
69+
*/
70+
public boolean hasStep() {
71+
return step != null;
72+
}
73+
74+
/**
75+
* Convenience method to get the apply payload from the step.
76+
*
77+
* @return the apply payload, or null if no step is set
78+
*/
79+
public APPLY getApply() {
80+
return step != null ? step.getApply() : null;
81+
}
82+
83+
/**
84+
* Convenience method to get the rollback payload from the step.
85+
*
86+
* @return the rollback payload, or null if no step is set or no rollback defined
87+
*/
88+
public ROLLBACK getRollback() {
89+
return step != null ? step.getRollback() : null;
90+
}
91+
92+
/**
93+
* Checks if this template has a rollback payload defined.
94+
*
95+
* @return true if a step is set and it has a rollback payload
96+
*/
97+
public boolean hasRollback() {
98+
return step != null && step.hasRollback();
99+
}
100+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright 2025 Flamingock (https://www.flamingock.io)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.flamingock.api.template;
17+
18+
import java.util.List;
19+
20+
/**
21+
* Abstract base class for templates with multiple steps.
22+
*
23+
* <p>Use this class when your template processes multiple operations, each with
24+
* its own apply and optional rollback. The YAML structure for this template type is:
25+
*
26+
* <pre>{@code
27+
* id: create-orders-collection
28+
* template: MongoChangeTemplate
29+
* steps:
30+
* - apply:
31+
* type: createCollection
32+
* collection: orders
33+
* rollback:
34+
* type: dropCollection
35+
* collection: orders
36+
* - apply:
37+
* type: insert
38+
* collection: orders
39+
* parameters:
40+
* documents:
41+
* - orderId: "ORD-001"
42+
* rollback:
43+
* type: delete
44+
* collection: orders
45+
* parameters:
46+
* filter: {}
47+
* }</pre>
48+
*
49+
* <p>The framework will automatically parse the steps from the YAML and inject
50+
* them via {@link #setSteps}.
51+
*
52+
* <p><b>Rollback Behavior:</b>
53+
* <ul>
54+
* <li>When a step fails, all previously successful steps are rolled back in reverse order</li>
55+
* <li>Steps without rollback operations are skipped during rollback</li>
56+
* <li>Rollback errors are logged but don't stop the rollback process</li>
57+
* </ul>
58+
*
59+
* @param <SHARED_CONFIG> the type of shared configuration
60+
* @param <APPLY> the type of the apply payload for each step
61+
* @param <ROLLBACK> the type of the rollback payload for each step
62+
*/
63+
public abstract class AbstractSteppableTemplate<SHARED_CONFIG, APPLY, ROLLBACK>
64+
extends AbstractChangeTemplate<SHARED_CONFIG, APPLY, ROLLBACK> {
65+
66+
protected List<TemplateStep<APPLY, ROLLBACK>> steps;
67+
68+
public AbstractSteppableTemplate(Class<?>... additionalReflectiveClass) {
69+
super(additionalReflectiveClass);
70+
}
71+
72+
/**
73+
* Sets the list of steps to execute.
74+
*
75+
* @param steps the list of template steps
76+
*/
77+
public void setSteps(List<TemplateStep<APPLY, ROLLBACK>> steps) {
78+
this.steps = steps;
79+
}
80+
81+
/**
82+
* Returns the list of steps.
83+
*
84+
* @return the list of template steps, or null if not set
85+
*/
86+
public List<TemplateStep<APPLY, ROLLBACK>> getSteps() {
87+
return steps;
88+
}
89+
90+
}

core/flamingock-core-api/src/main/java/io/flamingock/api/template/ChangeTemplate.java

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,17 @@
1515
*/
1616
package io.flamingock.api.template;
1717

18-
import java.util.List;
19-
2018
/**
2119
* Interface representing a reusable change template with configuration of type {@code CONFIG}.
2220
*
2321
* <p>This interface is commonly implemented by classes that act as templates for Changes
2422
* where a specific configuration needs to be injected and managed independently.
23+
*
24+
* <p>Templates should extend one of the abstract base classes:
25+
* <ul>
26+
* <li>{@link AbstractSimpleTemplate} - for templates with a single apply/rollback step</li>
27+
* <li>{@link AbstractSteppableTemplate} - for templates with multiple steps</li>
28+
* </ul>
2529
*/
2630
public interface ChangeTemplate<SHARED_CONFIG_FIELD, APPLY_FIELD, ROLLBACK_FIELD> extends ReflectionMetadataProvider {
2731

@@ -31,26 +35,6 @@ public interface ChangeTemplate<SHARED_CONFIG_FIELD, APPLY_FIELD, ROLLBACK_FIELD
3135

3236
void setConfiguration(SHARED_CONFIG_FIELD configuration);
3337

34-
/**
35-
* @deprecated Use {@link #setStepsPayload(List)} instead. Will be removed in a future release.
36-
*/
37-
@Deprecated
38-
void setApplyPayload(APPLY_FIELD applyPayload);
39-
40-
/**
41-
* @deprecated Use {@link #setStepsPayload(List)} instead. Will be removed in a future release.
42-
*/
43-
@Deprecated
44-
void setRollbackPayload(ROLLBACK_FIELD rollbackPayload);
45-
46-
void setStepsPayload(List<TemplateStep<APPLY_FIELD, ROLLBACK_FIELD>> stepsPayload);
47-
48-
List<TemplateStep<APPLY_FIELD, ROLLBACK_FIELD>> getStepsPayload();
49-
50-
default boolean hasStepsPayload() {
51-
return getStepsPayload() != null && !getStepsPayload().isEmpty();
52-
}
53-
5438
Class<SHARED_CONFIG_FIELD> getConfigurationClass();
5539

5640
Class<APPLY_FIELD> getApplyPayloadClass();

0 commit comments

Comments
 (0)