From b5787bbe6b6e8fda6bc943538acf1f119bc56926 Mon Sep 17 00:00:00 2001 From: James Maes Date: Thu, 5 Nov 2026 05:44:20 -0600 Subject: [PATCH 1/3] fix: align the geo data QBit with QQQ 4.1 Build against the published QQQ 4.1 core (qqq-bom-pom 4.1.0-RC.21). Mark City, Country and StateProvince with produceTableMetaData and add the setters QRecordEntity needs to discover their fields, and make the producer tolerate a table without fields. Update the producer test. Co-Authored-By: Claude Sonnet 5.5 --- pom.xml | 9 ++ .../qbits/geodata/GeoDataQBitProducer.java | 4 + .../kingsrook/qbits/geodata/model/City.java | 101 +++++++++++++++++- .../qbits/geodata/model/Country.java | 83 +++++++++++++- .../qbits/geodata/model/StateProvince.java | 74 ++++++++++++- .../geodata/GeoDataQBitProducerTest.java | 32 ++++++ 6 files changed, 300 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 138c223..5057969 100644 --- a/pom.xml +++ b/pom.xml @@ -51,6 +51,7 @@ 0.1.0 + 4.1.0-RC.21 21 21 UTF-8 @@ -58,6 +59,14 @@ + + + com.kingsrook.qqq + qqq-bom-pom + ${qqq.version} + pom + import + org.json json diff --git a/qbit-geo-data-core/src/main/java/com/kingsrook/qbits/geodata/GeoDataQBitProducer.java b/qbit-geo-data-core/src/main/java/com/kingsrook/qbits/geodata/GeoDataQBitProducer.java index 93af12e..80b2a0e 100644 --- a/qbit-geo-data-core/src/main/java/com/kingsrook/qbits/geodata/GeoDataQBitProducer.java +++ b/qbit-geo-data-core/src/main/java/com/kingsrook/qbits/geodata/GeoDataQBitProducer.java @@ -126,6 +126,10 @@ public class GeoDataQBitProducer implements QBitProducer *******************************************************************************/ private void updateForeignKeyReferences(QTableMetaData table) { + if(table.getFields() == null) + { + return; + } table.getFields().values().forEach(field -> { if(field.getPossibleValueSourceName() != null) diff --git a/qbit-geo-data-core/src/main/java/com/kingsrook/qbits/geodata/model/City.java b/qbit-geo-data-core/src/main/java/com/kingsrook/qbits/geodata/model/City.java index 35dbe4a..a349a10 100644 --- a/qbit-geo-data-core/src/main/java/com/kingsrook/qbits/geodata/model/City.java +++ b/qbit-geo-data-core/src/main/java/com/kingsrook/qbits/geodata/model/City.java @@ -14,7 +14,7 @@ import com.kingsrook.qqq.backend.core.model.data.QRecordEntity; import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.QMetaDataProducingEntity; -@QMetaDataProducingEntity(producePossibleValueSource = true) +@QMetaDataProducingEntity(produceTableMetaData = true, producePossibleValueSource = true) public class City extends QRecordEntity { public static final String TABLE_NAME = "city"; @@ -204,4 +204,103 @@ public class City extends QRecordEntity { return modifyDate; } + + + /******************************************************************************* + ** Setter for id (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setId(Integer id) + { + this.id = id; + } + + + /******************************************************************************* + ** Setter for stateProvinceId (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setStateProvinceId(Integer stateProvinceId) + { + this.stateProvinceId = stateProvinceId; + } + + + /******************************************************************************* + ** Setter for name (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setName(String name) + { + this.name = name; + } + + + /******************************************************************************* + ** Setter for asciiName (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setAsciiName(String asciiName) + { + this.asciiName = asciiName; + } + + + /******************************************************************************* + ** Setter for population (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setPopulation(Integer population) + { + this.population = population; + } + + + /******************************************************************************* + ** Setter for latitude (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setLatitude(BigDecimal latitude) + { + this.latitude = latitude; + } + + + /******************************************************************************* + ** Setter for longitude (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setLongitude(BigDecimal longitude) + { + this.longitude = longitude; + } + + + /******************************************************************************* + ** Setter for timezone (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setTimezone(String timezone) + { + this.timezone = timezone; + } + + + /******************************************************************************* + ** Setter for isActive (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setIsActive(Boolean isActive) + { + this.isActive = isActive; + } + + + /******************************************************************************* + ** Setter for createDate (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setCreateDate(Instant createDate) + { + this.createDate = createDate; + } + + + /******************************************************************************* + ** Setter for modifyDate (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setModifyDate(Instant modifyDate) + { + this.modifyDate = modifyDate; + } } diff --git a/qbit-geo-data-core/src/main/java/com/kingsrook/qbits/geodata/model/Country.java b/qbit-geo-data-core/src/main/java/com/kingsrook/qbits/geodata/model/Country.java index 8bac2bf..d0e4a83 100644 --- a/qbit-geo-data-core/src/main/java/com/kingsrook/qbits/geodata/model/Country.java +++ b/qbit-geo-data-core/src/main/java/com/kingsrook/qbits/geodata/model/Country.java @@ -13,7 +13,7 @@ import com.kingsrook.qqq.backend.core.model.data.QRecordEntity; import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.QMetaDataProducingEntity; -@QMetaDataProducingEntity(producePossibleValueSource = true) +@QMetaDataProducingEntity(produceTableMetaData = true, producePossibleValueSource = true) public class Country extends QRecordEntity { public static final String TABLE_NAME = "country"; @@ -171,4 +171,85 @@ public class Country extends QRecordEntity { return modifyDate; } + + + /******************************************************************************* + ** Setter for id (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setId(Integer id) + { + this.id = id; + } + + + /******************************************************************************* + ** Setter for alpha2Code (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setAlpha2Code(String alpha2Code) + { + this.alpha2Code = alpha2Code; + } + + + /******************************************************************************* + ** Setter for alpha3Code (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setAlpha3Code(String alpha3Code) + { + this.alpha3Code = alpha3Code; + } + + + /******************************************************************************* + ** Setter for numericCode (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setNumericCode(Integer numericCode) + { + this.numericCode = numericCode; + } + + + /******************************************************************************* + ** Setter for name (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setName(String name) + { + this.name = name; + } + + + /******************************************************************************* + ** Setter for officialName (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setOfficialName(String officialName) + { + this.officialName = officialName; + } + + + /******************************************************************************* + ** Setter for isActive (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setIsActive(Boolean isActive) + { + this.isActive = isActive; + } + + + /******************************************************************************* + ** Setter for createDate (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setCreateDate(Instant createDate) + { + this.createDate = createDate; + } + + + /******************************************************************************* + ** Setter for modifyDate (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setModifyDate(Instant modifyDate) + { + this.modifyDate = modifyDate; + } } diff --git a/qbit-geo-data-core/src/main/java/com/kingsrook/qbits/geodata/model/StateProvince.java b/qbit-geo-data-core/src/main/java/com/kingsrook/qbits/geodata/model/StateProvince.java index b55c33d..aee1018 100644 --- a/qbit-geo-data-core/src/main/java/com/kingsrook/qbits/geodata/model/StateProvince.java +++ b/qbit-geo-data-core/src/main/java/com/kingsrook/qbits/geodata/model/StateProvince.java @@ -13,7 +13,7 @@ import com.kingsrook.qqq.backend.core.model.data.QRecordEntity; import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.QMetaDataProducingEntity; -@QMetaDataProducingEntity(producePossibleValueSource = true) +@QMetaDataProducingEntity(produceTableMetaData = true, producePossibleValueSource = true) public class StateProvince extends QRecordEntity { public static final String TABLE_NAME = "stateProvince"; @@ -155,4 +155,76 @@ public class StateProvince extends QRecordEntity { return modifyDate; } + + + /******************************************************************************* + ** Setter for id (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setId(Integer id) + { + this.id = id; + } + + + /******************************************************************************* + ** Setter for countryId (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setCountryId(Integer countryId) + { + this.countryId = countryId; + } + + + /******************************************************************************* + ** Setter for code (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setCode(String code) + { + this.code = code; + } + + + /******************************************************************************* + ** Setter for name (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setName(String name) + { + this.name = name; + } + + + /******************************************************************************* + ** Setter for subdivisionType (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setSubdivisionType(String subdivisionType) + { + this.subdivisionType = subdivisionType; + } + + + /******************************************************************************* + ** Setter for isActive (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setIsActive(Boolean isActive) + { + this.isActive = isActive; + } + + + /******************************************************************************* + ** Setter for createDate (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setCreateDate(Instant createDate) + { + this.createDate = createDate; + } + + + /******************************************************************************* + ** Setter for modifyDate (QRecordEntity discovers a field only from a getter and setter pair). + *******************************************************************************/ + public void setModifyDate(Instant modifyDate) + { + this.modifyDate = modifyDate; + } } diff --git a/qbit-geo-data-core/src/test/java/com/kingsrook/qbits/geodata/GeoDataQBitProducerTest.java b/qbit-geo-data-core/src/test/java/com/kingsrook/qbits/geodata/GeoDataQBitProducerTest.java index 96134a8..136347b 100644 --- a/qbit-geo-data-core/src/test/java/com/kingsrook/qbits/geodata/GeoDataQBitProducerTest.java +++ b/qbit-geo-data-core/src/test/java/com/kingsrook/qbits/geodata/GeoDataQBitProducerTest.java @@ -78,6 +78,38 @@ class GeoDataQBitProducerTest + /******************************************************************************* + ** The enabled entities produce their tables, on the configured backend, with the + ** prefix; the possible value sources point at tables that exist. (On core 4.1 an + ** entity annotation only produces a table when it asks for it.) + *******************************************************************************/ + @Test + void testProduce_createsTablesAndPossibleValueSourcesPointAtThem() throws QException + { + QInstance qInstance = new QInstance(); + qInstance.addBackend(new QBackendMetaData().withName("rdbms")); + + new GeoDataQBitProducer() + .withConfig(new GeoDataQBitConfig().withBackendName("rdbms").withTableNamePrefix("geo") + .withEnableCountries(true).withEnableStateProvinces(true).withEnableCities(true)) + .produce(qInstance, "geo"); + + assertThat(qInstance.getTables().keySet()).contains("geo_country", "geo_stateProvince", "geo_city"); + assertThat(qInstance.getTable("geo_city").getBackendName()).isEqualTo("rdbms"); + assertThat(qInstance.getTable("geo_country").getPrimaryKeyField()).isEqualTo("id"); + assertThat(qInstance.getTable("geo_country").getFields().keySet()).contains("alpha2Code", "name", "isActive"); + assertThat(qInstance.getTable("geo_city").getFields().keySet()).contains("name"); + for(var pvs : qInstance.getPossibleValueSources().values()) + { + if(pvs.getTableName() != null) + { + assertThat(qInstance.getTable(pvs.getTableName())).as(pvs.getName()).isNotNull(); + } + } + } + + + /******************************************************************************* ** Test that producer stores config in QBit metadata. *******************************************************************************/ -- 2.54.0 From 6337bfe838283da376e65983311646ace32bdfa5 Mon Sep 17 00:00:00 2001 From: James Maes Date: Thu, 5 Nov 2026 07:16:52 -0600 Subject: [PATCH 2/3] build: start the 0.2.0 development line The published 0.1.0 release stays immutable, so the QQQ 4.1 alignment and the field-discovery fixes move the development revision to the next unpublished minor, 0.2.0-SNAPSHOT. Co-Authored-By: Claude Sonnet 5.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5057969..126517e 100644 --- a/pom.xml +++ b/pom.xml @@ -50,7 +50,7 @@ - 0.1.0 + 0.2.0-SNAPSHOT 4.1.0-RC.21 21 21 -- 2.54.0 From 5802fc4adc2b649299366ef629a1985b7abe5720 Mon Sep 17 00:00:00 2001 From: James Maes Date: Thu, 5 Nov 2026 08:37:17 -0600 Subject: [PATCH 3/3] build: converge JUnit on 5.10.0 so tests are discovered with the QQQ 4.1 BOM CI 4834 (verify 77965) failed with "TestEngine with ID 'junit-jupiter' failed to discover tests" and ran no test. The published qqq-bom-pom 4.1.0-RC.21 inherits junit-jupiter-engine and junit-jupiter-params at 6.0.2 from its parent qqq-parent-project. The project imported that BOM before its own junit-bom 5.10.0, so the engine and params resolved to 6.0.2 while junit-jupiter, the API and the platform stayed at 5.10.0; the mixed engine cannot start under Surefire 3.1.2. Import the pom's existing junit-bom 5.10.0 first (first import wins) so every JUnit artifact converges on 5.10.0. No version is added or upgraded; the parent and the QQQ BOM are unchanged. The module and revision relationships are unchanged. Co-Authored-By: Claude Sonnet 5.5 --- pom.xml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 126517e..4906a7e 100644 --- a/pom.xml +++ b/pom.xml @@ -59,6 +59,17 @@ + + + org.junit + junit-bom + 5.10.0 + pom + import + com.kingsrook.qqq @@ -72,13 +83,6 @@ json 20231013 - - org.junit - junit-bom - 5.10.0 - pom - import - org.assertj assertj-core -- 2.54.0