eva4j 1.0.13 → 1.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +314 -10
- package/COMMAND_EVALUATION.md +15 -16
- package/DOMAIN_YAML_GUIDE.md +576 -10
- package/FUTURE_FEATURES.md +1627 -1168
- package/README.md +318 -13
- package/bin/eva4j.js +34 -0
- package/config/defaults.json +1 -0
- package/design-system.md +797 -0
- package/docs/commands/EVALUATE_SYSTEM.md +994 -0
- package/docs/commands/GENERATE_ENTITIES.md +795 -6
- package/docs/commands/INDEX.md +10 -1
- package/examples/domain-endpoints-relations.yaml +353 -0
- package/examples/domain-endpoints-versioned.yaml +144 -0
- package/examples/domain-endpoints.yaml +135 -0
- package/examples/domain-events.yaml +166 -20
- package/examples/domain-listeners.yaml +212 -0
- package/examples/domain-one-to-many.yaml +1 -0
- package/examples/domain-one-to-one.yaml +1 -0
- package/examples/domain-ports.yaml +414 -0
- package/examples/domain-soft-delete.yaml +47 -44
- package/examples/system/notification.yaml +147 -0
- package/examples/system/product.yaml +185 -0
- package/examples/system/system.yaml +112 -0
- package/examples/system-report.html +971 -0
- package/examples/system.yaml +332 -0
- package/package.json +2 -1
- package/src/commands/build.js +714 -0
- package/src/commands/create.js +7 -3
- package/src/commands/detach.js +1 -0
- package/src/commands/evaluate-system.js +610 -0
- package/src/commands/generate-entities.js +1331 -49
- package/src/commands/generate-http-exchange.js +2 -0
- package/src/commands/generate-kafka-event.js +98 -11
- package/src/generators/base-generator.js +8 -1
- package/src/generators/postman-generator.js +188 -0
- package/src/generators/shared-generator.js +10 -0
- package/src/utils/config-manager.js +54 -0
- package/src/utils/context-builder.js +1 -0
- package/src/utils/domain-diagram.js +192 -0
- package/src/utils/domain-validator.js +970 -0
- package/src/utils/fake-data.js +376 -0
- package/src/utils/naming.js +3 -2
- package/src/utils/system-validator.js +434 -0
- package/src/utils/yaml-to-entity.js +302 -8
- package/templates/aggregate/AggregateMapper.java.ejs +3 -2
- package/templates/aggregate/AggregateRepository.java.ejs +8 -2
- package/templates/aggregate/AggregateRepositoryImpl.java.ejs +13 -3
- package/templates/aggregate/AggregateRoot.java.ejs +60 -2
- package/templates/aggregate/DomainEventHandler.java.ejs +27 -20
- package/templates/aggregate/DomainEventRecord.java.ejs +24 -8
- package/templates/aggregate/DomainEventSnapshot.java.ejs +46 -0
- package/templates/aggregate/JpaAggregateRoot.java.ejs +6 -0
- package/templates/aggregate/JpaRepository.java.ejs +5 -0
- package/templates/base/gradle/build.gradle.ejs +3 -2
- package/templates/base/root/AGENTS.md.ejs +306 -45
- package/templates/base/root/skill-build-domain-yaml-references-generate-entities.md.ejs +1663 -0
- package/templates/base/root/skill-build-system-yaml.ejs +1446 -0
- package/templates/base/root/system.yaml.ejs +97 -0
- package/templates/crud/ApplicationMapper.java.ejs +4 -0
- package/templates/crud/Controller.java.ejs +4 -4
- package/templates/crud/CreateCommand.java.ejs +4 -0
- package/templates/crud/CreateItemDto.java.ejs +4 -0
- package/templates/crud/CreateValueObjectDto.java.ejs +4 -0
- package/templates/crud/DeleteCommandHandler.java.ejs +10 -2
- package/templates/crud/EndpointsController.java.ejs +178 -0
- package/templates/crud/FindByQuery.java.ejs +17 -0
- package/templates/crud/FindByQueryHandler.java.ejs +57 -0
- package/templates/crud/ListQuery.java.ejs +1 -1
- package/templates/crud/ListQueryHandler.java.ejs +8 -8
- package/templates/crud/ScaffoldCommand.java.ejs +12 -0
- package/templates/crud/ScaffoldCommandHandler.java.ejs +43 -0
- package/templates/crud/ScaffoldQuery.java.ejs +13 -0
- package/templates/crud/ScaffoldQueryHandler.java.ejs +41 -0
- package/templates/crud/SubEntityAddCommand.java.ejs +21 -0
- package/templates/crud/SubEntityAddCommandHandler.java.ejs +43 -0
- package/templates/crud/SubEntityRemoveCommand.java.ejs +9 -0
- package/templates/crud/SubEntityRemoveCommandHandler.java.ejs +42 -0
- package/templates/crud/TransitionCommand.java.ejs +9 -0
- package/templates/crud/TransitionCommandHandler.java.ejs +39 -0
- package/templates/crud/UpdateCommand.java.ejs +4 -0
- package/templates/evaluate/report.html.ejs +1363 -0
- package/templates/kafka-event/DomainEventHandlerMethod.ejs +3 -1
- package/templates/kafka-event/Event.java.ejs +16 -0
- package/templates/kafka-listener/KafkaController.java.ejs +1 -1
- package/templates/kafka-listener/KafkaListenerClass.java.ejs +1 -1
- package/templates/kafka-listener/ListenerClass.java.ejs +65 -0
- package/templates/kafka-listener/ListenerCommand.java.ejs +31 -0
- package/templates/kafka-listener/ListenerCommandHandler.java.ejs +23 -0
- package/templates/kafka-listener/ListenerIntegrationEvent.java.ejs +37 -0
- package/templates/kafka-listener/ListenerMethod.java.ejs +1 -1
- package/templates/kafka-listener/ListenerNestedType.java.ejs +28 -0
- package/templates/mock/MockEvent.java.ejs +10 -0
- package/templates/mock/MockMessageBrokerImpl.java.ejs +35 -0
- package/templates/mock/MockMessageBrokerImplMethod.java.ejs +6 -0
- package/templates/mock/SpringEventListener.java.ejs +61 -0
- package/templates/ports/PortDomainModel.java.ejs +35 -0
- package/templates/ports/PortFeignAdapter.java.ejs +67 -0
- package/templates/ports/PortFeignClient.java.ejs +45 -0
- package/templates/ports/PortFeignConfig.java.ejs +24 -0
- package/templates/ports/PortInterface.java.ejs +45 -0
- package/templates/ports/PortNestedType.java.ejs +28 -0
- package/templates/ports/PortRequestDto.java.ejs +30 -0
- package/templates/ports/PortResponseDto.java.ejs +28 -0
- package/templates/postman/Collection.json.ejs +1 -1
- package/templates/postman/UnifiedCollection.json.ejs +185 -0
- package/templates/shared/configurations/eventPublicationConfig/EventPublicationSchemaConfig.java.ejs +109 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
package <%= packageName %>.<%= moduleName %>.application.dtos;
|
|
2
|
+
<% const needsBigDecimal = bodyFields && bodyFields.some(f => f.javaType === 'BigDecimal'); %>
|
|
3
|
+
<% const needsLocalDate = bodyFields && bodyFields.some(f => ['LocalDate','LocalDateTime','LocalTime'].includes(f.javaType)); %>
|
|
4
|
+
<% const needsInstant = bodyFields && bodyFields.some(f => f.javaType === 'Instant'); %>
|
|
5
|
+
<% const needsUUID = bodyFields && bodyFields.some(f => f.javaType === 'UUID'); %>
|
|
6
|
+
<% const needsList = bodyFields && bodyFields.some(f => f.javaType && f.javaType.startsWith('List')); %>
|
|
7
|
+
<% if (needsBigDecimal) { %>
|
|
8
|
+
import java.math.BigDecimal;
|
|
9
|
+
<% } %><% if (needsLocalDate) { %>
|
|
10
|
+
import java.time.LocalDate;
|
|
11
|
+
import java.time.LocalDateTime;
|
|
12
|
+
import java.time.LocalTime;
|
|
13
|
+
<% } %><% if (needsInstant) { %>
|
|
14
|
+
import java.time.Instant;
|
|
15
|
+
<% } %><% if (needsUUID) { %>
|
|
16
|
+
import java.util.UUID;
|
|
17
|
+
<% } %><% if (needsList) { %>
|
|
18
|
+
import java.util.List;
|
|
19
|
+
<% } %>
|
|
20
|
+
<% (nestedTypes || []).forEach(nt => { %>import <%= packageName %>.<%= moduleName %>.application.dtos.<%= nt.name %>;
|
|
21
|
+
<% }); %>
|
|
22
|
+
public record <%= dtoName %>(
|
|
23
|
+
<% if (bodyFields && bodyFields.length > 0) { %>
|
|
24
|
+
<% bodyFields.forEach((f, i) => { %>
|
|
25
|
+
<%- f.javaType %> <%= f.name %><%= i < bodyFields.length - 1 ? ',' : '' %>
|
|
26
|
+
<% }); %>
|
|
27
|
+
<% } else { %>
|
|
28
|
+
// TODO: Add request body fields
|
|
29
|
+
<% } %>
|
|
30
|
+
) {}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
package <%= packageName %>.<%= moduleName %>.infrastructure.adapters.<%= adapterPackage %>;
|
|
2
|
+
<% const needsBigDecimal = fields && fields.some(f => f.javaType === 'BigDecimal'); %>
|
|
3
|
+
<% const needsLocalDate = fields && fields.some(f => ['LocalDate','LocalDateTime','LocalTime'].includes(f.javaType)); %>
|
|
4
|
+
<% const needsInstant = fields && fields.some(f => f.javaType === 'Instant'); %>
|
|
5
|
+
<% const needsUUID = fields && fields.some(f => f.javaType === 'UUID'); %>
|
|
6
|
+
<% const needsList = fields && fields.some(f => f.javaType && f.javaType.startsWith('List')); %>
|
|
7
|
+
<% if (needsBigDecimal) { %>
|
|
8
|
+
import java.math.BigDecimal;
|
|
9
|
+
<% } %><% if (needsLocalDate) { %>
|
|
10
|
+
import java.time.LocalDate;
|
|
11
|
+
import java.time.LocalDateTime;
|
|
12
|
+
import java.time.LocalTime;
|
|
13
|
+
<% } %><% if (needsInstant) { %>
|
|
14
|
+
import java.time.Instant;
|
|
15
|
+
<% } %><% if (needsUUID) { %>
|
|
16
|
+
import java.util.UUID;
|
|
17
|
+
<% } %><% if (needsList) { %>
|
|
18
|
+
import java.util.List;
|
|
19
|
+
<% } %>
|
|
20
|
+
public record <%= dtoName %>(
|
|
21
|
+
<% if (fields && fields.length > 0) { %>
|
|
22
|
+
<% fields.forEach((f, i) => { %>
|
|
23
|
+
<%- f.javaType %> <%= f.name %><%= i < fields.length - 1 ? ',' : '' %>
|
|
24
|
+
<% }); %>
|
|
25
|
+
<% } else { %>
|
|
26
|
+
// TODO: Add response fields
|
|
27
|
+
<% } %>
|
|
28
|
+
) {}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
<%
|
|
2
|
+
/**
|
|
3
|
+
* UnifiedCollection.json.ejs
|
|
4
|
+
*
|
|
5
|
+
* Generates a single Postman 2.1.0 collection covering ALL modules in the
|
|
6
|
+
* system. The hierarchy is:
|
|
7
|
+
*
|
|
8
|
+
* {SystemName} API
|
|
9
|
+
* └── {ModuleName}
|
|
10
|
+
* └── {AggregateName}
|
|
11
|
+
* ├── POST Create {Agg}
|
|
12
|
+
* ├── GET Get {Agg} by ID
|
|
13
|
+
* ├── GET Get All {Agg}s
|
|
14
|
+
* ├── PUT Update {Agg}
|
|
15
|
+
* ├── DELETE Delete {Agg}
|
|
16
|
+
* └── PUT {Custom} {Agg} (confirm, cancel, …)
|
|
17
|
+
*
|
|
18
|
+
* Context expected:
|
|
19
|
+
* - systemName : string
|
|
20
|
+
* - collectionId : string (UUID)
|
|
21
|
+
* - port : number
|
|
22
|
+
* - modules : Array<ModuleCtx>
|
|
23
|
+
*
|
|
24
|
+
* ModuleCtx:
|
|
25
|
+
* - name : string (module name, e.g. "product")
|
|
26
|
+
* - aggregates : Array<AggregateCtx>
|
|
27
|
+
*
|
|
28
|
+
* AggregateCtx:
|
|
29
|
+
* - name : string (PascalCase, e.g. "Product")
|
|
30
|
+
* - trackUser : boolean
|
|
31
|
+
* - idType : string ("String" | "UUID" | "Long")
|
|
32
|
+
* - exampleId : string
|
|
33
|
+
* - operations : Array<OperationCtx> (when endpoints: section exists)
|
|
34
|
+
* - defaultCrud : boolean (true when no endpoints: section)
|
|
35
|
+
* - bodies : { [useCase]: object } (pre-generated JSON bodies keyed by useCase)
|
|
36
|
+
*
|
|
37
|
+
* OperationCtx:
|
|
38
|
+
* - useCase : string
|
|
39
|
+
* - method : string (GET, POST, PUT, PATCH, DELETE)
|
|
40
|
+
* - path : string (e.g. "/{id}" or "/publish")
|
|
41
|
+
* - basePath : string (e.g. "/products")
|
|
42
|
+
* - version : string (e.g. "v1")
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
function buildUrl(port, version, basePath, opPath) {
|
|
46
|
+
// Normalise: remove leading slash from basePath if present, and from opPath
|
|
47
|
+
let bPath = basePath.replace(/^\//, '');
|
|
48
|
+
let oPath = opPath.replace(/^\//, '');
|
|
49
|
+
|
|
50
|
+
// Build full path segments
|
|
51
|
+
const segments = ['api', version];
|
|
52
|
+
if (bPath) segments.push(...bPath.split('/').filter(Boolean));
|
|
53
|
+
if (oPath) segments.push(...oPath.split('/').filter(Boolean));
|
|
54
|
+
|
|
55
|
+
const raw = 'http://localhost:' + port + '/' + segments.join('/');
|
|
56
|
+
return { raw, segments, port: String(port) };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function hasBody(method) {
|
|
60
|
+
return method === 'POST' || method === 'PUT' || method === 'PATCH';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ----- Build the items tree ------------------------------------------------
|
|
64
|
+
const moduleItems = [];
|
|
65
|
+
|
|
66
|
+
for (const mod of modules) {
|
|
67
|
+
const aggregateItems = [];
|
|
68
|
+
|
|
69
|
+
for (const agg of mod.aggregates) {
|
|
70
|
+
const requestItems = [];
|
|
71
|
+
|
|
72
|
+
if (agg.operations && agg.operations.length > 0) {
|
|
73
|
+
// Endpoint-driven: use declared operations
|
|
74
|
+
for (const op of agg.operations) {
|
|
75
|
+
const url = buildUrl(port, op.version, op.basePath, op.path);
|
|
76
|
+
// Replace {id} with example ID
|
|
77
|
+
const rawUrl = url.raw.replace(/\{id\}/g, agg.exampleId);
|
|
78
|
+
const pathSegments = url.segments.map(s => s === '{id}' ? agg.exampleId : s);
|
|
79
|
+
|
|
80
|
+
const headers = [{ key: 'Content-Type', value: 'application/json', type: 'text' }];
|
|
81
|
+
if (agg.trackUser) {
|
|
82
|
+
headers.push({ key: 'X-User', value: 'system', type: 'text' });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const item = {
|
|
86
|
+
name: op.useCase,
|
|
87
|
+
request: {
|
|
88
|
+
method: op.method,
|
|
89
|
+
header: headers,
|
|
90
|
+
url: {
|
|
91
|
+
raw: rawUrl,
|
|
92
|
+
protocol: 'http',
|
|
93
|
+
host: ['localhost'],
|
|
94
|
+
port: String(port),
|
|
95
|
+
path: pathSegments
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
response: []
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
if (hasBody(op.method) && agg.bodies[op.useCase]) {
|
|
102
|
+
item.request.body = {
|
|
103
|
+
mode: 'raw',
|
|
104
|
+
raw: JSON.stringify(agg.bodies[op.useCase], null, 2),
|
|
105
|
+
options: { raw: { language: 'json' } }
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
requestItems.push(item);
|
|
110
|
+
}
|
|
111
|
+
} else if (agg.defaultCrud) {
|
|
112
|
+
// No endpoints section → generate 5 standard CRUD requests
|
|
113
|
+
const resource = agg.resourceNameKebab;
|
|
114
|
+
const crudOps = [
|
|
115
|
+
{ useCase: 'Create ' + agg.name, method: 'POST', path: '' },
|
|
116
|
+
{ useCase: 'Get ' + agg.name + ' by ID', method: 'GET', path: '/' + agg.exampleId },
|
|
117
|
+
{ useCase: 'Get All ' + agg.name + 's', method: 'GET', path: '' },
|
|
118
|
+
{ useCase: 'Update ' + agg.name, method: 'PUT', path: '/' + agg.exampleId },
|
|
119
|
+
{ useCase: 'Delete ' + agg.name, method: 'DELETE', path: '/' + agg.exampleId },
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
for (const op of crudOps) {
|
|
123
|
+
const url = buildUrl(port, 'v1', resource, op.path);
|
|
124
|
+
|
|
125
|
+
const headers = [{ key: 'Content-Type', value: 'application/json', type: 'text' }];
|
|
126
|
+
if (agg.trackUser) {
|
|
127
|
+
headers.push({ key: 'X-User', value: 'system', type: 'text' });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const item = {
|
|
131
|
+
name: op.useCase,
|
|
132
|
+
request: {
|
|
133
|
+
method: op.method,
|
|
134
|
+
header: headers,
|
|
135
|
+
url: {
|
|
136
|
+
raw: url.raw,
|
|
137
|
+
protocol: 'http',
|
|
138
|
+
host: ['localhost'],
|
|
139
|
+
port: String(port),
|
|
140
|
+
path: url.segments
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
response: []
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
if (hasBody(op.method) && agg.bodies['default']) {
|
|
147
|
+
item.request.body = {
|
|
148
|
+
mode: 'raw',
|
|
149
|
+
raw: JSON.stringify(agg.bodies['default'], null, 2),
|
|
150
|
+
options: { raw: { language: 'json' } }
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
requestItems.push(item);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (requestItems.length > 0) {
|
|
159
|
+
aggregateItems.push({
|
|
160
|
+
name: agg.name,
|
|
161
|
+
item: requestItems
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (aggregateItems.length > 0) {
|
|
167
|
+
moduleItems.push({
|
|
168
|
+
name: mod.name,
|
|
169
|
+
item: aggregateItems
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const collection = {
|
|
175
|
+
info: {
|
|
176
|
+
_postman_id: collectionId,
|
|
177
|
+
name: systemName + ' API',
|
|
178
|
+
description: 'Auto-generated unified API collection for all modules in ' + systemName + '.\nGenerated by eva4j with realistic fake data.',
|
|
179
|
+
schema: 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json',
|
|
180
|
+
version: '1.0.0'
|
|
181
|
+
},
|
|
182
|
+
item: moduleItems
|
|
183
|
+
};
|
|
184
|
+
%>
|
|
185
|
+
<%- JSON.stringify(collection, null, 2) %>
|
package/templates/shared/configurations/eventPublicationConfig/EventPublicationSchemaConfig.java.ejs
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
package <%= packageName %>.shared.infrastructure.configurations.eventPublicationConfig;
|
|
2
|
+
|
|
3
|
+
import java.util.Map;
|
|
4
|
+
import javax.sql.DataSource;
|
|
5
|
+
|
|
6
|
+
import org.hibernate.boot.model.relational.Namespace;
|
|
7
|
+
import org.hibernate.boot.model.relational.Sequence;
|
|
8
|
+
import org.hibernate.mapping.Table;
|
|
9
|
+
import org.hibernate.tool.schema.spi.SchemaFilter;
|
|
10
|
+
import org.hibernate.tool.schema.spi.SchemaFilterProvider;
|
|
11
|
+
import org.slf4j.Logger;
|
|
12
|
+
import org.slf4j.LoggerFactory;
|
|
13
|
+
import org.springframework.boot.ApplicationRunner;
|
|
14
|
+
import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
|
|
15
|
+
import org.springframework.context.annotation.Bean;
|
|
16
|
+
import org.springframework.context.annotation.Configuration;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Fixes Spring Modulith JPA event_publication table columns.
|
|
20
|
+
* <p>
|
|
21
|
+
* Hibernate maps the internal {@code JpaEventPublication} String fields
|
|
22
|
+
* as {@code varchar(255)} by default, which is too short for serialised
|
|
23
|
+
* domain event payloads.
|
|
24
|
+
* <p>
|
|
25
|
+
* This config does two things:
|
|
26
|
+
* <ol>
|
|
27
|
+
* <li>Excludes the {@code event_publication} table from Hibernate DDL auto
|
|
28
|
+
* so it never tries to ALTER columns back to {@code varchar(255)}.</li>
|
|
29
|
+
* <li>Runs an {@link ApplicationRunner} that ensures the columns are {@code TEXT}.</li>
|
|
30
|
+
* </ol>
|
|
31
|
+
*/
|
|
32
|
+
@Configuration
|
|
33
|
+
public class EventPublicationSchemaConfig implements HibernatePropertiesCustomizer {
|
|
34
|
+
|
|
35
|
+
private static final Logger log = LoggerFactory.getLogger(EventPublicationSchemaConfig.class);
|
|
36
|
+
|
|
37
|
+
@Override
|
|
38
|
+
public void customize(Map<String, Object> hibernateProperties) {
|
|
39
|
+
hibernateProperties.put(
|
|
40
|
+
"hibernate.hbm2ddl.schema_filter_provider",
|
|
41
|
+
new EventPublicationFilterProvider()
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@Bean
|
|
46
|
+
ApplicationRunner eventPublicationSchemaFix(DataSource dataSource) {
|
|
47
|
+
return args -> {
|
|
48
|
+
try (var conn = dataSource.getConnection()) {
|
|
49
|
+
var db = conn.getMetaData().getDatabaseProductName().toLowerCase();
|
|
50
|
+
String[] statements;
|
|
51
|
+
|
|
52
|
+
if (db.contains("postgre")) {
|
|
53
|
+
statements = new String[]{
|
|
54
|
+
"CREATE TABLE IF NOT EXISTS event_publication (id UUID NOT NULL PRIMARY KEY, completion_date TIMESTAMP, event_type TEXT NOT NULL, listener_id TEXT NOT NULL, publication_date TIMESTAMP, serialized_event TEXT NOT NULL)",
|
|
55
|
+
"ALTER TABLE event_publication ALTER COLUMN serialized_event TYPE TEXT",
|
|
56
|
+
"ALTER TABLE event_publication ALTER COLUMN event_type TYPE TEXT",
|
|
57
|
+
"ALTER TABLE event_publication ALTER COLUMN listener_id TYPE TEXT"
|
|
58
|
+
};
|
|
59
|
+
} else if (db.contains("mysql") || db.contains("maria")) {
|
|
60
|
+
statements = new String[]{
|
|
61
|
+
"CREATE TABLE IF NOT EXISTS event_publication (id VARCHAR(36) NOT NULL PRIMARY KEY, completion_date DATETIME, event_type TEXT NOT NULL, listener_id TEXT NOT NULL, publication_date DATETIME, serialized_event TEXT NOT NULL)",
|
|
62
|
+
"ALTER TABLE event_publication MODIFY COLUMN serialized_event TEXT",
|
|
63
|
+
"ALTER TABLE event_publication MODIFY COLUMN event_type TEXT",
|
|
64
|
+
"ALTER TABLE event_publication MODIFY COLUMN listener_id TEXT"
|
|
65
|
+
};
|
|
66
|
+
} else {
|
|
67
|
+
// H2 and other databases
|
|
68
|
+
statements = new String[]{
|
|
69
|
+
"CREATE TABLE IF NOT EXISTS event_publication (id UUID NOT NULL PRIMARY KEY, completion_date TIMESTAMP, event_type TEXT NOT NULL, listener_id TEXT NOT NULL, publication_date TIMESTAMP, serialized_event TEXT NOT NULL)",
|
|
70
|
+
"ALTER TABLE IF EXISTS event_publication ALTER COLUMN serialized_event TEXT",
|
|
71
|
+
"ALTER TABLE IF EXISTS event_publication ALTER COLUMN event_type TEXT",
|
|
72
|
+
"ALTER TABLE IF EXISTS event_publication ALTER COLUMN listener_id TEXT"
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
for (var sql : statements) {
|
|
77
|
+
try (var stmt = conn.createStatement()) {
|
|
78
|
+
stmt.execute(sql);
|
|
79
|
+
} catch (Exception e) {
|
|
80
|
+
// Column already TEXT or statement not applicable — safe to ignore
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
log.debug("event_publication columns verified (TEXT)");
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ── Hibernate Schema Filter ────────────────────────────────────────────
|
|
89
|
+
// Excludes event_publication from ddl-auto so Hibernate never tries
|
|
90
|
+
// to ALTER its columns back to varchar(255).
|
|
91
|
+
|
|
92
|
+
static class EventPublicationFilterProvider implements SchemaFilterProvider {
|
|
93
|
+
private static final SchemaFilter FILTER = new EventPublicationFilter();
|
|
94
|
+
|
|
95
|
+
@Override public SchemaFilter getCreateFilter() { return FILTER; }
|
|
96
|
+
@Override public SchemaFilter getDropFilter() { return FILTER; }
|
|
97
|
+
@Override public SchemaFilter getMigrateFilter() { return FILTER; }
|
|
98
|
+
@Override public SchemaFilter getValidateFilter() { return FILTER; }
|
|
99
|
+
@Override public SchemaFilter getTruncatorFilter() { return FILTER; }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
static class EventPublicationFilter implements SchemaFilter {
|
|
103
|
+
@Override public boolean includeNamespace(Namespace namespace) { return true; }
|
|
104
|
+
@Override public boolean includeSequence(Sequence sequence) { return true; }
|
|
105
|
+
@Override public boolean includeTable(Table table) {
|
|
106
|
+
return !"event_publication".equalsIgnoreCase(table.getName());
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|