From 069c104f43cf422a4d6ec19efbab85634f320c0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Manciot?= Date: Fri, 22 May 2026 08:49:10 +0200 Subject: [PATCH] feat: add platform and max_joins fields to SHOW LICENSE output Add platform-aware display to SHOW LICENSE command, defaulting to PRODUCTION when not platform-scoped. Update documentation with new platform and max_joins columns. Closed Issue #90 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../elastic/client/GatewayApi.scala | 1 + .../elastic/client/LicenseExecutorSpec.scala | 68 +++++++++++++++++++ documentation/sql/dql_statements.md | 8 ++- 3 files changed, 74 insertions(+), 3 deletions(-) diff --git a/core/src/main/scala/app/softnetwork/elastic/client/GatewayApi.scala b/core/src/main/scala/app/softnetwork/elastic/client/GatewayApi.scala index 12bf61b4..dd7e4586 100644 --- a/core/src/main/scala/app/softnetwork/elastic/client/GatewayApi.scala +++ b/core/src/main/scala/app/softnetwork/elastic/client/GatewayApi.scala @@ -1628,6 +1628,7 @@ class LicenseExecutor( val row = ListMap[String, Any]( "license_type" -> s"${mgr.licenseType}$trialNote$degradedNote", "trial" -> key.isTrial, + "platform" -> key.platform.map(_.name).getOrElse("PRODUCTION"), "max_materialized_views" -> formatQuota(mgr.quotas.maxMaterializedViews), "max_clusters" -> formatQuota(mgr.quotas.maxClusters), "max_result_rows" -> formatQuota(mgr.quotas.maxQueryResults), diff --git a/core/src/test/scala/app/softnetwork/elastic/client/LicenseExecutorSpec.scala b/core/src/test/scala/app/softnetwork/elastic/client/LicenseExecutorSpec.scala index bb53e4a6..3eac3a44 100644 --- a/core/src/test/scala/app/softnetwork/elastic/client/LicenseExecutorSpec.scala +++ b/core/src/test/scala/app/softnetwork/elastic/client/LicenseExecutorSpec.scala @@ -76,6 +76,8 @@ class LicenseExecutorSpec extends AnyFlatSpec with Matchers { row should contain key "license_type" row("license_type") shouldBe "Community" row("trial") shouldBe false + row should contain key "platform" + row("platform") shouldBe "PRODUCTION" row should contain key "max_materialized_views" row("max_materialized_views") shouldBe "3" row should contain key "max_clusters" @@ -116,6 +118,7 @@ class LicenseExecutorSpec extends AnyFlatSpec with Matchers { row("max_clusters") shouldBe "5" row("max_result_rows") shouldBe "1000000" row("max_concurrent_queries") shouldBe "50" + row("platform") shouldBe "PRODUCTION" row("expires_at") shouldBe "2026-12-31T23:59:59Z" row("days_remaining").asInstanceOf[Long] should be > 0L row("status") shouldBe "Active" @@ -191,6 +194,71 @@ class LicenseExecutorSpec extends AnyFlatSpec with Matchers { row("status") shouldBe "Active" } + it should "show platform field matching LicenseKey.platform when set" in { + val stagingManager = new LicenseManager { + override def validate(key: String): Either[LicenseError, LicenseKey] = + Left(InvalidLicense("test")) + override def hasFeature(feature: Feature): Boolean = true + override def quotas: Quota = Quota( + maxMaterializedViews = Some(25), + maxQueryResults = Some(500000), + maxConcurrentQueries = Some(25), + maxClusters = Some(2), + maxJoins = Some(2) + ) + override def licenseType: LicenseType = LicenseType.Pro + override def currentLicenseKey: LicenseKey = LicenseKey( + id = "test-staging", + licenseType = LicenseType.Pro, + features = Feature.values.toSet, + expiresAt = Some(Instant.parse("2026-12-31T23:59:59Z")), + platform = Some(Platform.Staging) + ) + } + val executor = new LicenseExecutor(strategy = mkStrategy(stagingManager)) + val row = execute(executor, ShowLicense) + + row("platform") shouldBe "STAGING" + row("license_type") shouldBe "Pro" + row("max_materialized_views") shouldBe "25" + row("max_clusters") shouldBe "2" + row("max_result_rows") shouldBe "500000" + row("max_concurrent_queries") shouldBe "25" + row("max_joins") shouldBe "2" + } + + it should "show DEVELOPMENT platform when LicenseKey has Development platform" in { + val devManager = new LicenseManager { + override def validate(key: String): Either[LicenseError, LicenseKey] = + Left(InvalidLicense("test")) + override def hasFeature(feature: Feature): Boolean = true + override def quotas: Quota = Quota( + maxMaterializedViews = Some(5), + maxQueryResults = Some(10000), + maxConcurrentQueries = Some(5), + maxClusters = Some(1), + maxJoins = Some(1) + ) + override def licenseType: LicenseType = LicenseType.Pro + override def currentLicenseKey: LicenseKey = LicenseKey( + id = "test-dev", + licenseType = LicenseType.Pro, + features = Feature.values.toSet, + expiresAt = Some(Instant.parse("2026-12-31T23:59:59Z")), + platform = Some(Platform.Development) + ) + } + val executor = new LicenseExecutor(strategy = mkStrategy(devManager)) + val row = execute(executor, ShowLicense) + + row("platform") shouldBe "DEVELOPMENT" + row("max_materialized_views") shouldBe "5" + row("max_clusters") shouldBe "1" + row("max_result_rows") shouldBe "10000" + row("max_concurrent_queries") shouldBe "5" + row("max_joins") shouldBe "1" + } + // ------------------------------------------------------------------------- // REFRESH LICENSE // ------------------------------------------------------------------------- diff --git a/documentation/sql/dql_statements.md b/documentation/sql/dql_statements.md index 30512ea6..586d3feb 100644 --- a/documentation/sql/dql_statements.md +++ b/documentation/sql/dql_statements.md @@ -1320,10 +1320,12 @@ Returns the current license type, quota values, expiration date, and grace statu |--------|-------------| | `license_type` | Current license tier (Community, Pro, Enterprise). Shows "(trial)" suffix for trial licenses, "(degraded)" suffix if degraded from a higher tier. | | `trial` | `true` if the license is a Pro trial, `false` otherwise | +| `platform` | Platform scope of the current license key (PRODUCTION, STAGING, DEVELOPMENT, INTEGRATION). Defaults to "PRODUCTION" when not platform-scoped. | | `max_materialized_views` | Maximum number of materialized views allowed, or "unlimited" | | `max_clusters` | Maximum number of federated clusters allowed, or "unlimited" | | `max_result_rows` | Maximum rows returned per query, or "unlimited" | | `max_concurrent_queries` | Maximum concurrent queries allowed, or "unlimited" | +| `max_joins` | Maximum number of JOIN operations allowed per query, or "unlimited" | | `expires_at` | License expiration timestamp, or "never" for Community | | `days_remaining` | Days until expiration, or -1 for Community (no expiry) | | `status` | "Active", or grace period details if expired | @@ -1334,9 +1336,9 @@ Returns the current license type, quota values, expiration date, and grace statu SHOW LICENSE; ``` -| license_type | trial | max_materialized_views | max_clusters | max_result_rows | max_concurrent_queries | expires_at | days_remaining | status | -|---|---|---|---|---|---|---|---|---| -| Community | false | 3 | 2 | 10000 | 5 | never | -1 | Active | +| license_type | trial | platform | max_materialized_views | max_clusters | max_result_rows | max_concurrent_queries | max_joins | expires_at | days_remaining | status | +|---|---|---|---|---|---|---|---|---|---|---| +| Community | false | PRODUCTION | 3 | 1 | 10000 | 5 | 1 | never | -1 | Active | 📊 1 row(s) (1ms) ---