eva4j 1.0.12 → 1.0.13

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.
@@ -5,7 +5,7 @@
5
5
  aggregates:
6
6
  - name: Order
7
7
  entities:
8
- - name: order
8
+ - name: Order
9
9
  isRoot: true
10
10
  tableName: orders
11
11
  audit:
@@ -67,7 +67,7 @@ aggregates:
67
67
 
68
68
  - name: Customer
69
69
  entities:
70
- - name: customer
70
+ - name: Customer
71
71
  isRoot: true
72
72
  tableName: customers
73
73
  audit:
@@ -5,7 +5,7 @@
5
5
  aggregates:
6
6
  - name: BlogPost
7
7
  entities:
8
- - name: blogPost
8
+ - name: BlogPost
9
9
  isRoot: true
10
10
  tableName: blog_posts
11
11
  auditable: true
@@ -41,7 +41,7 @@ aggregates:
41
41
  cascade: [PERSIST, MERGE, REMOVE]
42
42
  fetch: LAZY
43
43
 
44
- - name: comment
44
+ - name: Comment
45
45
  tableName: comments
46
46
  auditable: true
47
47
  fields:
@@ -5,7 +5,7 @@
5
5
  aggregates:
6
6
  - name: ShoppingCart
7
7
  entities:
8
- - name: shoppingCart
8
+ - name: ShoppingCart
9
9
  isRoot: true
10
10
  tableName: shopping_carts
11
11
  auditable: true
@@ -39,7 +39,7 @@ aggregates:
39
39
  cascade: [PERSIST, MERGE, REMOVE]
40
40
  fetch: LAZY
41
41
 
42
- - name: cartItem
42
+ - name: CartItem
43
43
  tableName: cart_items
44
44
  auditable: true
45
45
  fields:
@@ -127,7 +127,7 @@
127
127
  aggregates:
128
128
  - name: Order
129
129
  entities:
130
- - name: order
130
+ - name: Order
131
131
  isRoot: true
132
132
  tableName: orders
133
133
  audit:
@@ -6,7 +6,7 @@ aggregates:
6
6
  # User Management Aggregate
7
7
  - name: User
8
8
  entities:
9
- - name: user
9
+ - name: User
10
10
  isRoot: true
11
11
  tableName: users
12
12
  audit:
@@ -40,6 +40,7 @@ aggregates:
40
40
  - name: loginCount
41
41
  type: Integer
42
42
  readOnly: true
43
+ defaultValue: 0 # Initialized to 0 on creation
43
44
 
44
45
  # Readonly field - NOT in constructor or CreateDto
45
46
  # Use case: Calculated timestamp
@@ -57,7 +58,7 @@ aggregates:
57
58
  # Order Management Aggregate
58
59
  - name: Order
59
60
  entities:
60
- - name: order
61
+ - name: Order
61
62
  isRoot: true
62
63
  tableName: orders
63
64
  audit:
@@ -80,11 +81,13 @@ aggregates:
80
81
  - name: totalAmount
81
82
  type: BigDecimal
82
83
  readOnly: true
84
+ defaultValue: "0.00" # Starts at zero before items are added
83
85
 
84
86
  # Readonly field - count of items
85
87
  - name: itemCount
86
88
  type: Integer
87
89
  readOnly: true
90
+ defaultValue: 0 # Starts at zero
88
91
 
89
92
  # Hidden field - internal processing flag
90
93
  - name: processingToken
@@ -97,7 +100,7 @@ aggregates:
97
100
  mappedBy: order
98
101
  cascade: [PERSIST, MERGE, REMOVE]
99
102
 
100
- - name: orderItem
103
+ - name: OrderItem
101
104
  tableName: order_items
102
105
  fields:
103
106
  - name: id
@@ -116,6 +119,7 @@ aggregates:
116
119
  - name: subtotal
117
120
  type: BigDecimal
118
121
  readOnly: true
122
+ defaultValue: "0.00" # Calculated on creation
119
123
 
120
124
  relationships:
121
125
  - type: ManyToOne
@@ -125,7 +129,7 @@ aggregates:
125
129
  # Product Catalog Aggregate
126
130
  - name: Product
127
131
  entities:
128
- - name: product
132
+ - name: Product
129
133
  isRoot: true
130
134
  tableName: products
131
135
  audit:
@@ -147,6 +151,7 @@ aggregates:
147
151
  - name: stockLevel
148
152
  type: Integer
149
153
  readOnly: true
154
+ defaultValue: 0 # New products start with zero stock
150
155
 
151
156
  # Readonly field - last updated stock timestamp
152
157
  - name: stockUpdatedAt
@@ -166,7 +171,7 @@ aggregates:
166
171
  # Session Management Aggregate
167
172
  - name: Session
168
173
  entities:
169
- - name: session
174
+ - name: Session
170
175
  isRoot: true
171
176
  tableName: sessions
172
177
  fields:
@@ -191,6 +196,7 @@ aggregates:
191
196
  type: Boolean
192
197
  hidden: true
193
198
  readOnly: true
199
+ defaultValue: false # Sessions start as not revoked
194
200
 
195
201
  - name: createdAt
196
202
  type: LocalDateTime
@@ -6,7 +6,7 @@ aggregates:
6
6
  # AGREGADO 1: Customer
7
7
  - name: Customer
8
8
  entities:
9
- - name: customer
9
+ - name: Customer
10
10
  isRoot: true
11
11
  tableName: customers
12
12
  auditable: true
@@ -30,7 +30,7 @@ aggregates:
30
30
  cascade: [PERSIST, MERGE, REMOVE]
31
31
  fetch: LAZY
32
32
 
33
- - name: address
33
+ - name: Address
34
34
  tableName: customer_addresses
35
35
  fields:
36
36
  - name: id
@@ -77,7 +77,7 @@ aggregates:
77
77
  # AGREGADO 2: Supplier
78
78
  - name: Supplier
79
79
  entities:
80
- - name: supplier
80
+ - name: Supplier
81
81
  isRoot: true
82
82
  tableName: suppliers
83
83
  auditable: true
@@ -97,7 +97,7 @@ aggregates:
97
97
  - name: rating
98
98
  type: Integer
99
99
 
100
- - name: contract
100
+ - name: Contract
101
101
  tableName: contracts
102
102
  auditable: true
103
103
  fields:
@@ -133,7 +133,7 @@ aggregates:
133
133
  # AGREGADO 3: Inventory
134
134
  - name: Inventory
135
135
  entities:
136
- - name: inventory
136
+ - name: Inventory
137
137
  isRoot: true
138
138
  tableName: inventory
139
139
  auditable: true
@@ -169,7 +169,7 @@ aggregates:
169
169
  cascade: [PERSIST, MERGE]
170
170
  fetch: LAZY
171
171
 
172
- - name: stockMovement
172
+ - name: StockMovement
173
173
  tableName: stock_movements
174
174
  auditable: true
175
175
  fields:
@@ -5,7 +5,7 @@
5
5
  aggregates:
6
6
  - name: Order
7
7
  entities:
8
- - name: order
8
+ - name: Order
9
9
  isRoot: true
10
10
  tableName: orders
11
11
  audit:
@@ -29,7 +29,7 @@ aggregates:
29
29
  relationships:
30
30
  - type: OneToOne
31
31
  target: UserProfile
32
- mappedBy: User
32
+ mappedBy: user
33
33
  cascade: [PERSIST, MERGE, REMOVE]
34
34
  fetch: LAZY
35
35
 
@@ -11,7 +11,7 @@
11
11
  aggregates:
12
12
  - name: Project
13
13
  entities:
14
- - name: project
14
+ - name: Project
15
15
  isRoot: true
16
16
  tableName: projects
17
17
  audit:
@@ -11,7 +11,7 @@
11
11
  aggregates:
12
12
  - name: Order
13
13
  entities:
14
- - name: order
14
+ - name: Order
15
15
  isRoot: true
16
16
  tableName: orders
17
17
  audit:
@@ -6,7 +6,7 @@
6
6
  aggregates:
7
7
  - name: Product
8
8
  entities:
9
- - name: product
9
+ - name: Product
10
10
  isRoot: true
11
11
  tableName: products
12
12
  auditable: true
@@ -5,7 +5,7 @@
5
5
  aggregates:
6
6
  - name: Document
7
7
  entities:
8
- - name: document
8
+ - name: Document
9
9
  isRoot: true
10
10
  tableName: documents
11
11
  auditable: true
@@ -48,7 +48,7 @@ aggregates:
48
48
  cascade: [PERSIST, MERGE, REMOVE]
49
49
  fetch: LAZY
50
50
 
51
- - name: revision
51
+ - name: Revision
52
52
  tableName: document_revisions
53
53
  auditable: true
54
54
  fields:
@@ -66,7 +66,7 @@ aggregates:
66
66
  type: String
67
67
 
68
68
 
69
- - name: attachment
69
+ - name: Attachment
70
70
  tableName: document_attachments
71
71
  auditable: true
72
72
  fields:
@@ -1,7 +1,7 @@
1
1
  aggregates:
2
2
  - name: Order
3
3
  entities:
4
- - name: order
4
+ - name: Order
5
5
  isRoot: true
6
6
  tableName: orders
7
7
  audit:
@@ -5,7 +5,7 @@
5
5
  aggregates:
6
6
  - name: User
7
7
  entities:
8
- - name: user
8
+ - name: User
9
9
  isRoot: true
10
10
  tableName: users
11
11
  auditable: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eva4j",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "A powerful Node.js CLI for generating Spring Boot projects with modular architecture that enables efficient monolith-first development with seamless transition to microservices",
5
5
  "main": "bin/eva4j.js",
6
6
  "bin": {
@@ -242,8 +242,71 @@ function buildAnnotationString(validation) {
242
242
  return params.length === 0 ? `@${type}` : `@${type}(${params.join(', ')})`;
243
243
  }
244
244
 
245
+ /**
246
+ * Compute the Java literal for a defaultValue declared in domain.yaml.
247
+ * Returns a string ready to be emitted in a template (e.g. `0`, `"foo"`, `Status.ACTIVE`).
248
+ * Returns null for unsupported combinations — callers should guard before emitting.
249
+ *
250
+ * @param {*} rawValue - The raw value from YAML (string, number, boolean)
251
+ * @param {string} javaType - The resolved Java type (e.g. "String", "BigDecimal")
252
+ * @param {boolean} isEnum - Whether the field type is an enum
253
+ * @returns {string|null}
254
+ */
255
+ function computeJavaDefaultValue(rawValue, javaType, isEnum) {
256
+ if (rawValue === null || rawValue === undefined) return null;
257
+
258
+ const strValue = String(rawValue);
259
+
260
+ // Enum type: emit EnumType.VALUE
261
+ if (isEnum) {
262
+ return `${javaType}.${strValue}`;
263
+ }
264
+
265
+ switch (javaType) {
266
+ case 'String':
267
+ return `"${strValue}"`;
268
+ case 'Boolean':
269
+ return strValue.toLowerCase() === 'true' ? 'true' : 'false';
270
+ case 'Integer':
271
+ case 'int':
272
+ return strValue;
273
+ case 'Long':
274
+ case 'long':
275
+ return `${strValue}L`;
276
+ case 'Double':
277
+ case 'double':
278
+ case 'Float':
279
+ case 'float':
280
+ return strValue;
281
+ case 'BigDecimal':
282
+ return `new BigDecimal("${strValue}")`;
283
+ case 'LocalDateTime':
284
+ if (strValue === 'now') return 'LocalDateTime.now()';
285
+ return null; // arbitrary datetime strings not supported
286
+ case 'LocalDate':
287
+ if (strValue === 'now') return 'LocalDate.now()';
288
+ return null;
289
+ case 'LocalTime':
290
+ if (strValue === 'now') return 'LocalTime.now()';
291
+ return null;
292
+ case 'Instant':
293
+ if (strValue === 'now') return 'Instant.now()';
294
+ return null;
295
+ case 'UUID':
296
+ if (strValue === 'random') return 'UUID.randomUUID()';
297
+ return null;
298
+ default:
299
+ // Unknown type — cannot safely emit a literal
300
+ return null;
301
+ }
302
+ }
303
+
245
304
  function parseProperty(propData, valueObjectNames = [], aggregateEnums = []) {
246
- const { name, type, annotations = [], isValueObject = false, isEmbedded = false, enumValues, readOnly = false, hidden = false, validations = [], reference = null } = propData;
305
+ const { name, type, annotations = [], isValueObject = false, isEmbedded = false, enumValues, readOnly = false, hidden = false, validations = [], reference = null, defaultValue = null } = propData;
306
+
307
+ if (defaultValue !== null && !readOnly) {
308
+ console.warn(`⚠️ Field "${name}": "defaultValue" is only meaningful for readOnly fields. It will be ignored since readOnly is not set.`);
309
+ }
247
310
 
248
311
  if (reference !== null) {
249
312
  if (typeof reference !== 'object' || !reference.aggregate || typeof reference.aggregate !== 'string') {
@@ -308,7 +371,11 @@ function parseProperty(propData, valueObjectNames = [], aggregateEnums = []) {
308
371
  transitionMeta,
309
372
  autoInit,
310
373
  autoInitValue,
311
- reference
374
+ reference,
375
+ defaultValue,
376
+ javaDefaultValue: (readOnly && !autoInit && defaultValue !== null)
377
+ ? computeJavaDefaultValue(defaultValue, javaType, !!enumValues || isEnumType)
378
+ : null
312
379
  };
313
380
  }
314
381
 
@@ -84,7 +84,8 @@ public class <%= name %> {
84
84
 
85
85
  <% const creationFields = fields.filter(f => f.name !== 'id' && f.name !== 'createdAt' && f.name !== 'updatedAt' && f.name !== 'createdBy' && f.name !== 'updatedBy' && !f.readOnly && !f.autoInit); %>
86
86
  <% const autoInitFields = fields.filter(f => f.autoInit); %>
87
- <% if (creationFields.length > 0 || autoInitFields.length > 0) { %>
87
+ <% const defaultValueFields = fields.filter(f => f.readOnly && !f.autoInit && f.javaDefaultValue); %>
88
+ <% if (creationFields.length > 0 || autoInitFields.length > 0 || defaultValueFields.length > 0) { %>
88
89
  // Constructor for new entity creation (without id, audit fields, readOnly and auto-initialized fields)
89
90
  public <%= name %>(<% let paramIdx = 0; %><% creationFields.forEach((field, idx) => { %><% if (paramIdx > 0) { %>, <% } %><%- field.javaType %> <%= field.name %><% paramIdx++; %><% }); %>) {
90
91
  <% creationFields.forEach(field => { %>
@@ -92,6 +93,9 @@ public class <%= name %> {
92
93
  <% }); %>
93
94
  <% autoInitFields.forEach(field => { %>
94
95
  this.<%= field.name %> = <%- field.javaType %>.<%= field.autoInitValue %>;
96
+ <% }); %>
97
+ <% defaultValueFields.forEach(field => { %>
98
+ this.<%= field.name %> = <%- field.javaDefaultValue %>;
95
99
  <% }); %>
96
100
  }
97
101
  <% } %>
@@ -51,7 +51,8 @@ public class <%= name %> {
51
51
 
52
52
  <% const creationFields = fields.filter(f => f.name !== 'id' && f.name !== 'createdAt' && f.name !== 'updatedAt' && f.name !== 'createdBy' && f.name !== 'updatedBy' && !f.readOnly && !f.autoInit); %>
53
53
  <% const autoInitFields = fields.filter(f => f.autoInit); %>
54
- <% if (creationFields.length > 0 || autoInitFields.length > 0) { %>
54
+ <% const defaultValueFields = fields.filter(f => f.readOnly && !f.autoInit && f.javaDefaultValue); %>
55
+ <% if (creationFields.length > 0 || autoInitFields.length > 0 || defaultValueFields.length > 0) { %>
55
56
  // Constructor for new entity creation (without id, audit fields, readOnly and auto-initialized fields)
56
57
  public <%= name %>(<% let paramIdx = 0; %><% creationFields.forEach((field, idx) => { %><% if (paramIdx > 0) { %>, <% } %><%- field.javaType %> <%= field.name %><% paramIdx++; %><% }); %>) {
57
58
  <% creationFields.forEach(field => { %>
@@ -59,6 +60,9 @@ public class <%= name %> {
59
60
  <% }); %>
60
61
  <% autoInitFields.forEach(field => { %>
61
62
  this.<%= field.name %> = <%- field.javaType %>.<%= field.autoInitValue %>;
63
+ <% }); %>
64
+ <% defaultValueFields.forEach(field => { %>
65
+ this.<%= field.name %> = <%- field.javaDefaultValue %>;
62
66
  <% }); %>
63
67
  }
64
68
  <% } %>
@@ -75,7 +75,8 @@ if (audit && audit.trackUser) {
75
75
  <% } %>@Embedded
76
76
  <% } %><% if (field.isEnum) { %>@Enumerated(EnumType.STRING)
77
77
  <% } %><% if (field.reference) { %>/** Cross-aggregate reference → <%= field.reference.aggregate %><% if (field.reference.module) { %> (module: <%= field.reference.module %>)<% } %> */
78
- <% } %>private <%- field.isValueObject ? field.javaTypeJpa : field.javaType %> <%= field.name %>;
78
+ <% } %><% if (field.javaDefaultValue) { %>@Builder.Default
79
+ <% } %>private <%- field.isValueObject ? field.javaTypeJpa : field.javaType %> <%= field.name %><% if (field.javaDefaultValue) { %> = <%- field.javaDefaultValue %><% } %>;
79
80
  <% } %>
80
81
  <% }); %>
81
82
  <% relationships.forEach(rel => { %>
@@ -85,7 +85,8 @@ if (audit && audit.trackUser) {
85
85
  <% } else if (field.javaType === 'Long' || field.javaType === 'Integer') { %>@GeneratedValue(strategy = GenerationType.IDENTITY)
86
86
  <% } %><% } %>@Column(name = "<%= field.name.replace(/([A-Z])/g, '_$1').toLowerCase() %>")
87
87
  <% if (field.reference) { %>/** Cross-aggregate reference → <%= field.reference.aggregate %><% if (field.reference.module) { %> (module: <%= field.reference.module %>)<% } %> */
88
- <% } %>private <%- field.javaType %> <%= field.name %>;
88
+ <% } %><% if (field.javaDefaultValue) { %>@Builder.Default
89
+ <% } %>private <%- field.javaType %> <%= field.name %><% if (field.javaDefaultValue) { %> = <%- field.javaDefaultValue %><% } %>;
89
90
  <% } %>
90
91
  <% }); %>
91
92
  <% relationships.forEach(rel => { %>