Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add table stripe_subscription_item #39

Merged
merged 4 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions docs/tables/stripe_subscription_item.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
title: "Steampipe Table: stripe_subscription_item - Query Stripe Subscriptions using SQL"
description: "Query the items associaated with a Stripe Subscription."
---

# Table: stripe_subscription_item - Query Stripe Subscription Items using SQL

Stripe Subscriptions is a service within Stripe that allows businesses to manage recurring billing for their customers. Subscription Items provide details including price, quantity, and billing thresholds.

## Table Usage Guide

The `stripe_subscription_item` table in Steampipe provides detailed information about subscription records in your Stripe account. This table allows you, as a financial analyst or developer, to query subscription-specific details, including the status, customer, start and end dates, billing cycle, pricing plans, discounts, and metadata. You can leverage this table to analyze active or canceled subscriptions, monitor revenue streams, identify subscriptions with specific plans or discounts, and more. The schema outlines the attributes of a Stripe subscription, such as the subscription ID, customer information, pricing details, discount information, and metadata, enabling a comprehensive view of your subscription data.

**Important Notes**
- You must specify a `subscription_id` in a where or join clause in order to use this table.

## Examples

### List details for a subscription
Explore all the stripe subscriptions.

```sql+postgres
select
*
from
stripe_subscription_item
where
subscription_id = 'sub_1Oo64zCWwOK68BLnfPDrQWIX'
```

```sql+sqlite
select
*
from
stripe_subscription_item
where
subscription_id = 'sub_1Oo64zCWwOK68BLnfPDrQWIX'
```

### Retrieve subscription items with applied discounts
Identify subscription items from a specific subscription that have discounts applied.

```sql+postgres
select
subscription_id,
plan,
price -> 'discounts' as discounts
from
stripe_subscription_item
where
subscription_id = 'sub_1Oo64zCWwOK68BLnfPDrQWIX'
and (price -> 'discounts') is not null;
```

```sql+sqlite
select
subscription_id,
plan,
json_extract(price, '$.discounts') as discounts
from
stripe_subscription_item
where
subscription_id = 'sub_1Oo64zCWwOK68BLnfPDrQWIX'
and json_extract(price, '$.discounts') is not null;
```

### Retrieve plan details for a subscription item
Fetch detailed information about plans associated with a specific subscription, including their activity status, billing scheme, ID, usage type, and tiers.

```sql+postgres
select
subscription_id,
plan ->> 'active' as is_active,
plan -> 'billingScheme' as billing_scheme,
plan ->> 'id' as plan_id,
plan ->> 'usageType' as usage_type,
plan ->> 'tiers' as plan_tiers
from
from
stripe_subscription_item
where
subscription_id = 'sub_1Oo64zCWwOK68BLnfPDrQWIX';
```

```sql+sqlite
select
subscription_id,
json_extract(plan, '$.active') as is_active,
json_extract(plan, '$.billingScheme') as billing_scheme,
json_extract(plan, '$.id') as plan_id,
json_extract(plan, '$.usageType') as usage_type,
json_extract(plan, '$.tiers') as plan_tiers
from
stripe_subscription_item
where
subscription_id = 'sub_1Oo64zCWwOK68BLnfPDrQWIX';
```
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.22.4
toolchain go1.22.6

require (
github.com/stripe/stripe-go v70.15.0+incompatible
github.com/stripe/stripe-go/v76 v76.0.0
github.com/turbot/steampipe-plugin-sdk/v5 v5.10.4
)

Expand Down
5 changes: 3 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -554,8 +554,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stripe/stripe-go v70.15.0+incompatible h1:hNML7M1zx8RgtepEMlxyu/FpVPrP7KZm1gPFQquJQvM=
github.com/stripe/stripe-go v70.15.0+incompatible/go.mod h1:A1dQZmO/QypXmsL0T8axYZkSN/uA/T/A64pfKdBAMiY=
github.com/stripe/stripe-go/v76 v76.0.0 h1:XmXcsaznrtrmncLKJhTxwXL78+AHiEO4cqdUITxAp/g=
github.com/stripe/stripe-go/v76 v76.0.0/go.mod h1:rw1MxjlAKKcZ+3FOXgTHgwiOa2ya6CPq6ykpJ0Q6Po4=
github.com/tkrajina/go-reflector v0.5.6 h1:hKQ0gyocG7vgMD2M3dRlYN6WBBOmdoOzJ6njQSepKdE=
github.com/tkrajina/go-reflector v0.5.6/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
github.com/turbot/go-kit v0.10.0-rc.0 h1:kd+jp2ibbIV33Hc8SsMAN410Dl9Pz6SJ40axbKUlSoA=
Expand Down Expand Up @@ -694,6 +694,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
Expand Down
10 changes: 2 additions & 8 deletions stripe/common_columns.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package stripe
import (
"context"

"github.com/stripe/stripe-go"
"github.com/stripe/stripe-go/v76"
"github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto"
"github.com/turbot/steampipe-plugin-sdk/v5/memoize"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
Expand All @@ -25,12 +25,6 @@ func commonColumns(c []*plugin.Column) []*plugin.Column {
// if the caching is required other than per connection, build a cache key for the call and use it in Memoize.
var getAccountMemoized = plugin.HydrateFunc(getAccountUncached).Memoize(memoize.WithCacheKeyFunction(getAccountCacheKey))

// declare a wrapper hydrate function to call the memoized function
// - this is required when a memoized function is used for a column definition
func getAccount(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
return getAccountMemoized(ctx, d, h)
}

func getAccountId(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
acc, err := getAccountMemoized(ctx, d, h)
if err != nil {
Expand All @@ -53,7 +47,7 @@ func getAccountUncached(ctx context.Context, d *plugin.QueryData, h *plugin.Hydr
return nil, err
}

item, err := conn.Account.Get()
item, err := conn.Accounts.Get()
if err != nil {
plugin.Logger(ctx).Error("stripe_account.listAccount", "query_error", err)
return nil, err
Expand Down
2 changes: 1 addition & 1 deletion stripe/error.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package stripe

import (
"github.com/stripe/stripe-go"
"github.com/stripe/stripe-go/v76"
)

func isNotFoundError(err error) bool {
Expand Down
17 changes: 9 additions & 8 deletions stripe/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@ func Plugin(ctx context.Context) *plugin.Plugin {
ShouldIgnoreError: isNotFoundError,
},
TableMap: map[string]*plugin.Table{
"stripe_account": tableStripeAccount(ctx),
"stripe_charge": tableStripeCharge(ctx),
"stripe_coupon": tableStripeCoupon(ctx),
"stripe_customer": tableStripeCustomer(ctx),
"stripe_invoice": tableStripeInvoice(ctx),
"stripe_plan": tableStripePlan(ctx),
"stripe_product": tableStripeProduct(ctx),
"stripe_subscription": tableStripeSubscription(ctx),
"stripe_account": tableStripeAccount(ctx),
"stripe_charge": tableStripeCharge(ctx),
"stripe_coupon": tableStripeCoupon(ctx),
"stripe_customer": tableStripeCustomer(ctx),
"stripe_invoice": tableStripeInvoice(ctx),
"stripe_plan": tableStripePlan(ctx),
"stripe_product": tableStripeProduct(ctx),
"stripe_subscription": tableStripeSubscription(ctx),
"stripe_subscription_item": tableStripeSubscriptionItem(ctx),
},
}
return p
Expand Down
13 changes: 10 additions & 3 deletions stripe/table_stripe_account.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,19 @@ func tableStripeAccount(ctx context.Context) *plugin.Table {
}
}

func listAccount(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
item, err := getAccount(ctx, d, h)
func listAccount(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData) (interface{}, error) {
conn, err := connect(ctx, d)
if err != nil {
plugin.Logger(ctx).Error("stripe_customer.listAccount", "query_error", err)
plugin.Logger(ctx).Error("stripe_account.listAccount", "connection_error", err)
return nil, err
}

item, err := conn.Accounts.Get()
if err != nil {
plugin.Logger(ctx).Error("stripe_account.listAccount", "query_error", err)
return nil, err
}

d.StreamListItem(ctx, item)
return nil, nil
}
2 changes: 1 addition & 1 deletion stripe/table_stripe_charge.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package stripe
import (
"context"

"github.com/stripe/stripe-go"
"github.com/stripe/stripe-go/v76"
"github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin/transform"
Expand Down
2 changes: 1 addition & 1 deletion stripe/table_stripe_coupon.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package stripe
import (
"context"

"github.com/stripe/stripe-go"
"github.com/stripe/stripe-go/v76"
"github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin/transform"
Expand Down
2 changes: 1 addition & 1 deletion stripe/table_stripe_customer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package stripe
import (
"context"

"github.com/stripe/stripe-go"
"github.com/stripe/stripe-go/v76"
"github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin/transform"
Expand Down
2 changes: 1 addition & 1 deletion stripe/table_stripe_invoice.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package stripe
import (
"context"

"github.com/stripe/stripe-go"
"github.com/stripe/stripe-go/v76"

"github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
Expand Down
2 changes: 1 addition & 1 deletion stripe/table_stripe_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package stripe
import (
"context"

"github.com/stripe/stripe-go"
"github.com/stripe/stripe-go/v76"
"github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin/transform"
Expand Down
2 changes: 1 addition & 1 deletion stripe/table_stripe_product.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package stripe
import (
"context"

"github.com/stripe/stripe-go"
"github.com/stripe/stripe-go/v76"
"github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin/transform"
Expand Down
17 changes: 11 additions & 6 deletions stripe/table_stripe_subscription.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package stripe
import (
"context"

"github.com/stripe/stripe-go"
"github.com/stripe/stripe-go/v76"
"github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin/transform"
Expand Down Expand Up @@ -88,14 +88,19 @@ func listSubscription(ctx context.Context, d *plugin.QueryData, _ *plugin.Hydrat

// Exact values can leverage optional key quals for optimal caching
q := d.EqualsQuals
if q["customer_id"] != nil {
params.Customer = q["customer_id"].GetStringValue()

customerId := q["customer_id"].GetStringValue()
if customerId != "" {
params.Customer = &customerId
}

if q["collection_method"] != nil {
params.CollectionMethod = stripe.String(q["collection_method"].GetStringValue())
}
if q["status"] != nil {
params.Status = q["status"].GetStringValue()

status := q["status"].GetStringValue()
if status != "" {
params.Status = &status
}

// Comparison values
Expand All @@ -116,7 +121,7 @@ func listSubscription(ctx context.Context, d *plugin.QueryData, _ *plugin.Hydrat
}
params.CreatedRange.GreaterThanOrEqual = tsSecs
case "=":
params.Created = tsSecs
params.Created = &tsSecs
case "<=":
if params.CreatedRange == nil {
params.CreatedRange = &stripe.RangeQueryParams{}
Expand Down
79 changes: 79 additions & 0 deletions stripe/table_stripe_subscription_item.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package stripe

import (
"context"
//"time"

"github.com/stripe/stripe-go/v76"
"github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin/transform"
)

func tableStripeSubscriptionItem(ctx context.Context) *plugin.Table {
return &plugin.Table{
Name: "stripe_subscription_item",
Description: "Subscription Items in Stripe represent the individual products that a customer is subscribed to.",
List: &plugin.ListConfig{
KeyColumns: plugin.SingleColumn("subscription_id"),
Hydrate: listSubscriptionItem,
},
Columns: commonColumns([]*plugin.Column{
// Add columns relevant to SubscriptionItems here
{Name: "id", Type: proto.ColumnType_STRING, Description: "Unique identifier for the subscription."},
{Name: "plan", Type: proto.ColumnType_JSON, Transform: transform.FromField("Plan"), Description: "A plan represents a billing configuration. (Deprecated)"},
{Name: "price", Type: proto.ColumnType_JSON, Transform: transform.FromField("Price"), Description: "A price represents a unit cost for a product, specifying the amount, currency, and billing frequency."},
{Name: "subscription_id", Type: proto.ColumnType_STRING, Transform: transform.FromField("Subscription"), Description: "The ID of the subscription this item belongs to."},
{Name: "usage_record_summaries", Type: proto.ColumnType_JSON, Hydrate: listUsageRecordSummaries, Transform: transform.FromValue()},
}),
}
}

// listSubscriptionItem lists all subscription items
func listSubscriptionItem(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData) (interface{}, error) {
conn, err := connect(ctx, d)
if err != nil {
plugin.Logger(ctx).Error("stripe_subscription.listSubscriptionItem", "connection_error", err)
return nil, err
}

subscription_id := d.EqualsQuals["subscription_id"].GetStringValue()
plugin.Logger(ctx).Debug("stripe_subscription.listSubscriptionItem", "subscription_id", subscription_id)

params := &stripe.SubscriptionItemListParams{
Subscription: stripe.String(subscription_id),
}

i := conn.SubscriptionItems.List(params)

for i.Next() {
d.StreamListItem(ctx, i.SubscriptionItem())
}

return nil, nil
}

func listUsageRecordSummaries(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
item := h.Item.(*stripe.SubscriptionItem)

plugin.Logger(ctx).Debug("stripe_subscription.listUsageRecordSummaries", "item", item)

conn, err := connect(ctx, d)
if err != nil {
plugin.Logger(ctx).Error("stripe_subscription.listSubscriptionItem", "connection_error", err)
return nil, err
}

params := &stripe.SubscriptionItemUsageRecordSummariesParams{
SubscriptionItem: stripe.String(item.ID),
}

var summaries []*stripe.UsageRecordSummary
u := conn.SubscriptionItems.UsageRecordSummaries(params)
for u.Next() {
summary := u.UsageRecordSummary()
summaries = append(summaries, summary)
}

return summaries, nil
}
Loading
Loading