diff --git a/components/engine/engine-numbering/src/main/java/org/eclipse/dirigible/components/engine/numbering/DocumentNumberEndpoint.java b/components/engine/engine-numbering/src/main/java/org/eclipse/dirigible/components/engine/numbering/DocumentNumberEndpoint.java index 0951ee2705..6206c1e751 100644 --- a/components/engine/engine-numbering/src/main/java/org/eclipse/dirigible/components/engine/numbering/DocumentNumberEndpoint.java +++ b/components/engine/engine-numbering/src/main/java/org/eclipse/dirigible/components/engine/numbering/DocumentNumberEndpoint.java @@ -121,8 +121,10 @@ public ResponseEntity> list() { if (materialized.contains(entry.getKey() + "|" + value.getKey())) { continue; } - views.add(new SeriesView(entry.getKey(), value.getKey(), value.getValue(), base.prefix(), base.size(), 0, 1, - DocumentNumberService.render(base.prefix(), base.size(), 1), true, true)); + // A virtual row previews exactly what its first allocation will materialize: the + // base row's shape AND counter (the base is the tenant's seedable template). + views.add(new SeriesView(entry.getKey(), value.getKey(), value.getValue(), base.prefix(), base.size(), base.counter(), + base.counter() + 1, DocumentNumberService.render(base.prefix(), base.size(), base.counter() + 1), true, true)); } } return ResponseEntity.ok(views); diff --git a/components/engine/engine-numbering/src/main/java/org/eclipse/dirigible/components/engine/numbering/DocumentNumberStore.java b/components/engine/engine-numbering/src/main/java/org/eclipse/dirigible/components/engine/numbering/DocumentNumberStore.java index d242605223..88d9bb12b0 100644 --- a/components/engine/engine-numbering/src/main/java/org/eclipse/dirigible/components/engine/numbering/DocumentNumberStore.java +++ b/components/engine/engine-numbering/src/main/java/org/eclipse/dirigible/components/engine/numbering/DocumentNumberStore.java @@ -42,10 +42,12 @@ *
  • the management surface writes {@code PREFIX} / {@code SIZE} / the counter reset;
  • *
  • allocation writes only {@code COUNTER}, via {@code COUNTER = COUNTER + 1} - with one * deliberate exception: the first allocation for a NEW PARTITION of a declared series materializes - * that partition's row, copying the shape from the series' base ({@code ""}-partition) row. - * Partition values are data (company ids), so no artefact can pre-provision them; the base row is - * the tenant's configured default they inherit. The copy happens once, at row birth - it never - * overwrites anything.
  • + * that partition's row, copying the shape AND the counter from the series' base + * ({@code ""}-partition) row. Partition values are data (company ids), so no artefact can + * pre-provision them; the base row is the tenant's configured template they inherit - including the + * starting point, so seeding the base row's next value BEFORE the first document works (a + * zero-started partition silently ignored the seed, observed live). The copy happens once, at row + * birth - it never overwrites anything. * * *

    @@ -215,14 +217,18 @@ void provision(String series, String partition, String prefix, int size) throws if (exists(connection, series, partition)) { return; } - insertRow(connection, series, partition, prefix, size); + insertRow(connection, series, partition, prefix, size, 0L); } } /** - * Materializes a NEW partition row of a declared series, inheriting the shape of the series' base - * ({@code ""}-partition) row - the tenant's configured default. Partition values are data, so this - * is the only place a partition row can be born. + * Materializes a NEW partition row of a declared series, inheriting the shape AND the counter of + * the series' base ({@code ""}-partition) row - the tenant's configured template. The counter is + * inherited because the base row is the only thing an operator CAN seed before a partition's first + * allocation (on a fresh tenant nothing marks the series partitioned yet, so the settings page + * offers the base row's next value): starting the partition at zero instead silently discarded the + * seed and the first document rendered ...0001. Partition values are data, so this is the only + * place a partition row can be born. * * @param connection the connection (autocommit) * @param series the series identity @@ -236,11 +242,12 @@ private void materializePartition(Connection connection, String series, String p + "] is not declared for this tenant - declare it in a .numbers artefact"); } Allocation base = read(connection, series, ""); - insertRow(connection, series, partition, base.prefix(), base.size()); + insertRow(connection, series, partition, base.prefix(), base.size(), base.value()); } - /** Inserts one series row with a zero counter, tolerating a concurrent identical insert. */ - private void insertRow(Connection connection, String series, String partition, String prefix, int size) throws SQLException { + /** Inserts one series row with the given counter, tolerating a concurrent identical insert. */ + private void insertRow(Connection connection, String series, String partition, String prefix, int size, long counter) + throws SQLException { String sql = SqlFactory.getNative(connection) .insert() .into(TABLE_NAME) @@ -253,7 +260,7 @@ private void insertRow(Connection connection, String series, String partition, S try (PreparedStatement statement = connection.prepareStatement(sql)) { statement.setString(1, series); statement.setString(2, partition); - statement.setLong(3, 0L); + statement.setLong(3, counter); statement.setString(4, prefix == null ? "" : prefix); statement.setInt(5, size); statement.executeUpdate(); diff --git a/components/resources/application-core/src/main/resources/META-INF/dirigible/application-core/i18n/bg-BG/shell.json b/components/resources/application-core/src/main/resources/META-INF/dirigible/application-core/i18n/bg-BG/shell.json index 37063dce02..8c360d7e52 100644 --- a/components/resources/application-core/src/main/resources/META-INF/dirigible/application-core/i18n/bg-BG/shell.json +++ b/components/resources/application-core/src/main/resources/META-INF/dirigible/application-core/i18n/bg-BG/shell.json @@ -110,7 +110,7 @@ "numberingNext": "Следващ", "numberingExample": "Следващ номер:", "numberingSaved": "Записано", - "numberingShapeTemplate": "Броячите живеят в редовете за отделните партиции по-долу; нова партиция се появява при първата си употреба, наследявайки тази форма.", + "numberingShapeTemplate": "Броячите живеят в редовете за отделните партиции по-долу; нова партиция се появява при първата си употреба, наследявайки тази форма и началния ѝ брояч.", "tenantConfigLabels": { "name": "Име", "subtitle": "Подзаглавие", diff --git a/components/resources/application-core/src/main/resources/META-INF/dirigible/application-core/i18n/en-US/shell.json b/components/resources/application-core/src/main/resources/META-INF/dirigible/application-core/i18n/en-US/shell.json index 9429e0280a..821689315a 100644 --- a/components/resources/application-core/src/main/resources/META-INF/dirigible/application-core/i18n/en-US/shell.json +++ b/components/resources/application-core/src/main/resources/META-INF/dirigible/application-core/i18n/en-US/shell.json @@ -110,7 +110,7 @@ "numberingNext": "Next", "numberingExample": "Next number:", "numberingSaved": "Saved", - "numberingShapeTemplate": "Counters live on the per-partition rows below; a new partition appears on its first use, inheriting this shape.", + "numberingShapeTemplate": "Counters live on the per-partition rows below; a new partition appears on its first use, inheriting this shape and its starting counter.", "tenantConfigLabels": { "name": "Name", "subtitle": "Subtitle", diff --git a/components/resources/resources-application/src/main/resources/META-INF/dirigible/application/views/_settings.html b/components/resources/resources-application/src/main/resources/META-INF/dirigible/application/views/_settings.html index 2648f2d54f..eac0fd366f 100644 --- a/components/resources/resources-application/src/main/resources/META-INF/dirigible/application/views/_settings.html +++ b/components/resources/resources-application/src/main/resources/META-INF/dirigible/application/views/_settings.html @@ -217,7 +217,7 @@ diff --git a/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/NumberingSdkIT.java b/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/NumberingSdkIT.java index 9e3900099f..803442860b 100644 --- a/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/NumberingSdkIT.java +++ b/tests/tests-integrations/src/main/java/org/eclipse/dirigible/integration/tests/api/NumberingSdkIT.java @@ -267,6 +267,27 @@ void aDeclaredPartitionSourceLabelsRowsAndSeedsCountersBeforeFirstUse() throws E }, ASSERTION_TIMEOUT_SECONDS); } + @Test + void aFreshPartitionInheritsTheBaseRowsSeededCounter() { + publishDeclarationAndController(); + + restAssuredExecutor.execute(() -> { + // On a fresh tenant nothing marks the series partitioned yet, so the base row is the only + // thing an operator CAN seed before the first document. Seed it... + given().contentType(ContentType.JSON) + .body("{\"series\": \"" + SERIES + "\", \"partition\": \"\", \"next\": 300}") + .when() + .put("/services/core/numbering") + .then() + .statusCode(204); + // ...and the FIRST allocation of a brand-new partition must render exactly the seed - the + // partition materializes inheriting the base row's shape AND counter (a zero-started + // partition silently discarded the seed: the first document rendered ...0001). + assertEquals("T-0300", allocate("/next/FRESHSEED"), "a fresh partition's first number is the base row's seeded next value"); + assertEquals("T-0301", allocate("/next/FRESHSEED"), "and it continues from there"); + }, ASSERTION_TIMEOUT_SECONDS); + } + @Test void aNewTenantGetsTheDeclaredSeriesWithItsOwnSequence() throws Exception { publishDeclarationAndController();