Skip to content

Commit 27fa396

Browse files
dmealingclaude
andcommitted
feat(metadata): SP-G Java recon Unit7 — converge physical db* onto cross-port logical attrs + drop dead DDL/migration vestiges
Removes Java's residual physical db* attr vocabulary so the metadata-module registry manifest byte-matches the cross-port canonical (residual EMPTY). Converged logical-equivalent db* → cross-port logical names (already on field.base via MetaField since Unit 4): - dbType="jsonb" (typed owned-object storage) → field.object @storage="jsonb"; migrated OMDB consumers (SimpleMappingHandlerDB.isJsonbField, GenericSQLDriver.isJsonbField). - dbNullable → @required (inverted), dbLength → @maxlength, dbPrecision → @precision, dbScale → @scale; migrated codegen-mustache HelperRegistry. - dbColumnType / column kept (already registered on field.base; the @dbColumnType value vocabulary remains in CoreDBMetaDataProvider as the single cross-port home consumed by OMDB + codegen-spring + codegen-kotlin). Dropped as dead DDL/migration vestiges (no live runtime consumer; schema is TS-owned per ADR-0015, OMDB is pure data-access): - field/object: dbForeignKey, dbIndex, dbUnique, previousName - identity: dbIndexName, dbSequenceName, dbTablespace - removed PreviousNameAttrTest + meta.rename.json (migration-rename only). CoreDBMetaDataProvider.registerTypes now registers no field/object/identity attrs — all cross-port logical attrs live on field.base. Gate stays @Ignore/@disabled (Unit 8 flips it); confirmed locally the metadata-module runner passes (residual EMPTY). Verified: metadata 925, codegen-base 31, codegen-mustache 35, omdb 37, codegen-spring/codegen-kotlin green, integration-tests 68 (Testcontainers persistence-conformance + api-contract). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 5d173c8 commit 27fa396

14 files changed

Lines changed: 123 additions & 254 deletions

File tree

fixtures/registry-conformance/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,16 @@ Detail per port:
259259
through the loader's validation, OMDB, `codegen-spring`, and `codegen-kotlin`
260260
(all consume the current Java attrs). It is tracked as a dedicated follow-on,
261261
NOT a silent omission, and the canonical is **not** edited (it is correct).
262+
**Update (Phase 2 complete):** every divergence above has since been reconciled
263+
unit-by-unit — the final piece, the physical `db*` vocabulary, was converged in
264+
SP-G Unit 7 (the logical-equivalent attrs `dbType`/`dbIndex`/`dbLength`/
265+
`dbNullable`/`dbPrecision`/`dbScale`/`dbUnique` mapped onto the cross-port
266+
`dbColumnType`/`db.indexed`/`maxLength`/required-ness/`precision`/`scale`/`unique`
267+
+ owned-object `@storage="jsonb"`, with consumers in `omdb` + `codegen-mustache`
268+
migrated; the DDL/migration-only remnants `dbForeignKey`/`previousName`/
269+
`dbIndexName`/`dbSequenceName`/`dbTablespace` dropped as dead under ADR-0015).
270+
The Java manifest now byte-matches the canonical (residual EMPTY); the gate stays
271+
`@Ignore`/`@Disabled` only until SP-G Unit 8 flips it atomically with CI wiring.
262272

263273
## Regenerating the canonical
264274

server/java/codegen-base/src/test/resources/schema-validation/valid-inline-attributes.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"name": "productId",
2020
"subType": "long",
2121
"@column": "product_id",
22-
"@dbNullable": false,
22+
"@required": true,
2323
"children": [
2424
{
2525
"validator": {
@@ -59,7 +59,7 @@
5959
"name": "price",
6060
"subType": "double",
6161
"@column": "price",
62-
"@dbScale": 2,
62+
"@scale": 2,
6363
"children": [
6464
{
6565
"validator": {
@@ -90,7 +90,6 @@
9090
"name": "categoryId",
9191
"subType": "int",
9292
"@column": "category_id",
93-
"@dbForeignKey": "categories.id",
9493
"@isOptional": true
9594
}
9695
},

server/java/codegen-base/src/test/resources/template-test-metadata.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"field.string": {
2323
"name": "username",
2424
"@column": "username",
25-
"@dbNullable": "false",
25+
"@required": true,
2626
"children": [
2727
{
2828
"validator.required": {}

server/java/codegen-mustache/src/main/java/com/metaobjects/generator/mustache/HelperRegistry.java

Lines changed: 31 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -595,20 +595,21 @@ private String getTableName(MetaObject metaObject) {
595595
}
596596

597597
/**
598-
* Determine if a field should be nullable based on validators.
599-
* Returns the explicit dbNullable attribute if present, otherwise analyzes
600-
* the field's validators to determine if it's required (not nullable).
598+
* Determine if a field should be nullable.
599+
* Honors the cross-port logical {@code @required} marker if present (nullable = !required,
600+
* SP-G Unit 7 — replaces the legacy {@code @dbNullable} physical attr), otherwise
601+
* analyzes the field's validators to determine if it's required (not nullable).
601602
*/
602603
private boolean isFieldNullable(MetaField metaField) {
603-
// Check for explicit dbNullable attribute first
604-
if (metaField.hasMetaAttr("dbNullable")) {
604+
// Honor the explicit logical @required marker first (cross-port name).
605+
if (metaField.hasMetaAttr(MetaField.ATTR_REQUIRED)) {
605606
try {
606-
boolean explicitNullable = Boolean.parseBoolean(
607-
metaField.getMetaAttr("dbNullable").getValueAsString());
608-
log.debug("Using explicit dbNullable: {} for field: {}", explicitNullable, metaField.getName());
609-
return explicitNullable;
607+
boolean required = Boolean.parseBoolean(
608+
metaField.getMetaAttr(MetaField.ATTR_REQUIRED).getValueAsString());
609+
log.debug("Using explicit @required: {} for field: {}", required, metaField.getName());
610+
return !required;
610611
} catch (Exception e) {
611-
log.warn("Invalid dbNullable value for field {}, falling back to validator analysis",
612+
log.warn("Invalid @required value for field {}, falling back to validator analysis",
612613
metaField.getName());
613614
}
614615
}
@@ -624,19 +625,20 @@ private boolean isFieldNullable(MetaField metaField) {
624625

625626
/**
626627
* Get the database column length for a field.
627-
* Returns the explicit dbLength attribute if present, otherwise analyzes
628-
* validators to determine appropriate length constraints.
628+
* Returns the explicit logical {@code @maxLength} attribute if present (cross-port name,
629+
* SP-G Unit 7 — replaces the legacy {@code @dbLength}), otherwise analyzes validators to
630+
* determine appropriate length constraints.
629631
*/
630632
private Optional<Integer> getFieldColumnLength(MetaField metaField) {
631-
// Check for explicit dbLength attribute first
632-
if (metaField.hasMetaAttr("dbLength")) {
633+
// Check for explicit logical @maxLength attribute first (cross-port name).
634+
if (metaField.hasMetaAttr(MetaField.ATTR_MAX_LENGTH)) {
633635
try {
634636
int explicitLength = Integer.parseInt(
635-
metaField.getMetaAttr("dbLength").getValueAsString());
636-
log.debug("Using explicit dbLength: {} for field: {}", explicitLength, metaField.getName());
637+
metaField.getMetaAttr(MetaField.ATTR_MAX_LENGTH).getValueAsString());
638+
log.debug("Using explicit @maxLength: {} for field: {}", explicitLength, metaField.getName());
637639
return Optional.of(explicitLength);
638640
} catch (NumberFormatException e) {
639-
log.warn("Invalid dbLength value for field {}, falling back to validator analysis",
641+
log.warn("Invalid @maxLength value for field {}, falling back to validator analysis",
640642
metaField.getName());
641643
}
642644
}
@@ -649,36 +651,25 @@ private Optional<Integer> getFieldColumnLength(MetaField metaField) {
649651
return validatorLength;
650652
}
651653

652-
// Check for maxLength attribute (common pattern)
653-
if (metaField.hasMetaAttr("maxLength")) {
654-
try {
655-
int maxLength = Integer.parseInt(
656-
metaField.getMetaAttr("maxLength").getValueAsString());
657-
log.debug("Using maxLength attribute: {} for field: {}", maxLength, metaField.getName());
658-
return Optional.of(maxLength);
659-
} catch (NumberFormatException e) {
660-
log.warn("Invalid maxLength value for field {}", metaField.getName());
661-
}
662-
}
663-
664654
log.debug("No length constraint found for field: {}", metaField.getName());
665655
return Optional.empty();
666656
}
667657

668658
/**
669659
* Get the database precision for numeric fields.
670-
* Returns the explicit dbPrecision attribute if present, otherwise returns
660+
* Returns the explicit logical {@code @precision} attribute if present (cross-port name,
661+
* SP-G Unit 7 — replaces the legacy {@code @dbPrecision}), otherwise returns
671662
* empty Optional as precision is typically database-specific.
672663
*/
673664
private Optional<Integer> getFieldPrecision(MetaField metaField) {
674-
if (metaField.hasMetaAttr("dbPrecision")) {
665+
if (metaField.hasMetaAttr(MetaField.ATTR_PRECISION)) {
675666
try {
676667
int precision = Integer.parseInt(
677-
metaField.getMetaAttr("dbPrecision").getValueAsString());
678-
log.debug("Using explicit dbPrecision: {} for field: {}", precision, metaField.getName());
668+
metaField.getMetaAttr(MetaField.ATTR_PRECISION).getValueAsString());
669+
log.debug("Using explicit @precision: {} for field: {}", precision, metaField.getName());
679670
return Optional.of(precision);
680671
} catch (NumberFormatException e) {
681-
log.warn("Invalid dbPrecision value for field {}", metaField.getName());
672+
log.warn("Invalid @precision value for field {}", metaField.getName());
682673
}
683674
}
684675

@@ -687,18 +678,19 @@ private Optional<Integer> getFieldPrecision(MetaField metaField) {
687678

688679
/**
689680
* Get the database scale for numeric fields.
690-
* Returns the explicit dbScale attribute if present, otherwise returns
681+
* Returns the explicit logical {@code @scale} attribute if present (cross-port name,
682+
* SP-G Unit 7 — replaces the legacy {@code @dbScale}), otherwise returns
691683
* empty Optional as scale is typically database-specific.
692684
*/
693685
private Optional<Integer> getFieldScale(MetaField metaField) {
694-
if (metaField.hasMetaAttr("dbScale")) {
686+
if (metaField.hasMetaAttr(MetaField.ATTR_SCALE)) {
695687
try {
696688
int scale = Integer.parseInt(
697-
metaField.getMetaAttr("dbScale").getValueAsString());
698-
log.debug("Using explicit dbScale: {} for field: {}", scale, metaField.getName());
689+
metaField.getMetaAttr(MetaField.ATTR_SCALE).getValueAsString());
690+
log.debug("Using explicit @scale: {} for field: {}", scale, metaField.getName());
699691
return Optional.of(scale);
700692
} catch (NumberFormatException e) {
701-
log.warn("Invalid dbScale value for field {}", metaField.getName());
693+
log.warn("Invalid @scale value for field {}", metaField.getName());
702694
}
703695
}
704696

0 commit comments

Comments
 (0)