From e5130772c48e51886df341c5344be781ba39c983 Mon Sep 17 00:00:00 2001 From: Richard Crowley Date: Mon, 8 Jun 2026 10:20:30 -0700 Subject: [PATCH 1/2] Distinguish HA from non-HA SKUs in JSON output The other output formats do this already but the JSON output just duplicated each object. This patch adds the same kind of distinguishing fields that other outputy formats use. --- internal/cmd/size/cluster.go | 18 ++++++++++++++++-- internal/cmd/size/cluster_test.go | 6 +++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/internal/cmd/size/cluster.go b/internal/cmd/size/cluster.go index 53d1b7d1..f926d495 100644 --- a/internal/cmd/size/cluster.go +++ b/internal/cmd/size/cluster.go @@ -169,8 +169,18 @@ type ClusterSKUSingleEngine struct { orig *planetscale.ClusterSKU } +type clusterSKUJSON struct { + *planetscale.ClusterSKU + Configuration string `json:"configuration"` + Replicas string `json:"replicas"` +} + func (c *ClusterSKU) MarshalJSON() ([]byte, error) { - return json.MarshalIndent(c.orig, "", " ") + return json.MarshalIndent(&clusterSKUJSON{ + ClusterSKU: c.orig, + Configuration: c.Configuration, + Replicas: c.Replicas, + }, "", " ") } func (c *ClusterSKU) MarshalCSVValue() interface{} { @@ -178,7 +188,11 @@ func (c *ClusterSKU) MarshalCSVValue() interface{} { } func (c *ClusterSKUSingleEngine) MarshalJSON() ([]byte, error) { - return json.MarshalIndent(c.orig, "", " ") + return json.MarshalIndent(&clusterSKUJSON{ + ClusterSKU: c.orig, + Configuration: c.Configuration, + Replicas: c.Replicas, + }, "", " ") } func (c *ClusterSKUSingleEngine) MarshalCSVValue() interface{} { diff --git a/internal/cmd/size/cluster_test.go b/internal/cmd/size/cluster_test.go index 5a41c250..0b2256da 100644 --- a/internal/cmd/size/cluster_test.go +++ b/internal/cmd/size/cluster_test.go @@ -110,8 +110,8 @@ func TestSizeCluster_ListCmd_PostgreSQL(t *testing.T) { // PostgreSQL clusters use ClusterSKUSingleEngine type (no engine column, has configuration and replicas) // Each cluster shows twice: once as HA and once as single node res := []*ClusterSKUSingleEngine{ - {orig: orig[0]}, - {orig: orig[0]}, + {Configuration: "highly available", Replicas: "2", orig: orig[0]}, + {Configuration: "single node", Replicas: "0", orig: orig[0]}, } c.Assert(buf.String(), qt.JSONEquals, res) @@ -158,7 +158,7 @@ func TestSizeCluster_ListCmd_MySQL(t *testing.T) { // MySQL uses ClusterSKUSingleEngine type (no engine column, but has configuration and replicas) res := []*ClusterSKUSingleEngine{ - {orig: orig[0]}, + {Configuration: "highly available", Replicas: "2", orig: orig[0]}, } c.Assert(buf.String(), qt.JSONEquals, res) From 109152cd1fd832226ef41a1b6733f3f97e02e32f Mon Sep 17 00:00:00 2001 From: Richard Crowley Date: Mon, 8 Jun 2026 11:37:24 -0700 Subject: [PATCH 2/2] Plumb ReplicaRate through as Rate for single-node sizes --- internal/cmd/size/cluster.go | 11 +++++++++++ internal/cmd/size/cluster_test.go | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/internal/cmd/size/cluster.go b/internal/cmd/size/cluster.go index f926d495..06364294 100644 --- a/internal/cmd/size/cluster.go +++ b/internal/cmd/size/cluster.go @@ -153,6 +153,7 @@ type ClusterSKU struct { Replicas string `header:"replicas" json:"replicas"` orig *planetscale.ClusterSKU + rate *int64 } // ClusterSKUSingleEngine is the format for single-engine views (--engine mysql or --engine postgresql). @@ -167,10 +168,12 @@ type ClusterSKUSingleEngine struct { Replicas string `header:"replicas" json:"replicas"` orig *planetscale.ClusterSKU + rate *int64 } type clusterSKUJSON struct { *planetscale.ClusterSKU + Rate *int64 `json:"rate"` Configuration string `json:"configuration"` Replicas string `json:"replicas"` } @@ -178,6 +181,7 @@ type clusterSKUJSON struct { func (c *ClusterSKU) MarshalJSON() ([]byte, error) { return json.MarshalIndent(&clusterSKUJSON{ ClusterSKU: c.orig, + Rate: c.rate, Configuration: c.Configuration, Replicas: c.Replicas, }, "", " ") @@ -190,6 +194,7 @@ func (c *ClusterSKU) MarshalCSVValue() interface{} { func (c *ClusterSKUSingleEngine) MarshalJSON() ([]byte, error) { return json.MarshalIndent(&clusterSKUJSON{ ClusterSKU: c.orig, + Rate: c.rate, Configuration: c.Configuration, Replicas: c.Replicas, }, "", " ") @@ -275,6 +280,7 @@ func toClusterSKUs(items []clusterSKUWithEngine, onlyMetal bool) []*ClusterSKU { Configuration: "highly available", Replicas: "2", orig: item.sku, + rate: item.sku.Rate, }) // Single node version using replica_rate (only for non-metal clusters) @@ -291,6 +297,7 @@ func toClusterSKUs(items []clusterSKUWithEngine, onlyMetal bool) []*ClusterSKU { Configuration: "single node", Replicas: "0", orig: item.sku, + rate: item.sku.ReplicaRate, }) } } else { @@ -306,6 +313,7 @@ func toClusterSKUs(items []clusterSKUWithEngine, onlyMetal bool) []*ClusterSKU { Configuration: "highly available", Replicas: "2", orig: item.sku, + rate: item.sku.Rate, }) } } @@ -336,6 +344,7 @@ func toClusterSKUsSingleEngine(items []clusterSKUWithEngine, onlyMetal bool) []* Configuration: "highly available", Replicas: "2", orig: item.sku, + rate: item.sku.Rate, }) // Single node version using replica_rate (only for non-metal clusters) @@ -351,6 +360,7 @@ func toClusterSKUsSingleEngine(items []clusterSKUWithEngine, onlyMetal bool) []* Configuration: "single node", Replicas: "0", orig: item.sku, + rate: item.sku.ReplicaRate, }) } } else { @@ -365,6 +375,7 @@ func toClusterSKUsSingleEngine(items []clusterSKUWithEngine, onlyMetal bool) []* Configuration: "highly available", Replicas: "2", orig: item.sku, + rate: item.sku.Rate, }) } } diff --git a/internal/cmd/size/cluster_test.go b/internal/cmd/size/cluster_test.go index 0b2256da..17a1f1cf 100644 --- a/internal/cmd/size/cluster_test.go +++ b/internal/cmd/size/cluster_test.go @@ -110,8 +110,8 @@ func TestSizeCluster_ListCmd_PostgreSQL(t *testing.T) { // PostgreSQL clusters use ClusterSKUSingleEngine type (no engine column, has configuration and replicas) // Each cluster shows twice: once as HA and once as single node res := []*ClusterSKUSingleEngine{ - {Configuration: "highly available", Replicas: "2", orig: orig[0]}, - {Configuration: "single node", Replicas: "0", orig: orig[0]}, + {Configuration: "highly available", Replicas: "2", orig: orig[0], rate: orig[0].Rate}, + {Configuration: "single node", Replicas: "0", orig: orig[0], rate: orig[0].ReplicaRate}, } c.Assert(buf.String(), qt.JSONEquals, res) @@ -158,7 +158,7 @@ func TestSizeCluster_ListCmd_MySQL(t *testing.T) { // MySQL uses ClusterSKUSingleEngine type (no engine column, but has configuration and replicas) res := []*ClusterSKUSingleEngine{ - {Configuration: "highly available", Replicas: "2", orig: orig[0]}, + {Configuration: "highly available", Replicas: "2", orig: orig[0], rate: orig[0].Rate}, } c.Assert(buf.String(), qt.JSONEquals, res)