postgres

package
v1.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 3, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package postgres provides a PostgreSQL Store implementation for Ledger using Grove ORM.

Index

Constants

This section is empty.

Variables

View Source
var Migrations = migrate.NewGroup("ledger")

Migrations is the grove migration group for the Ledger store.

Functions

This section is empty.

Types

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store implements store.Store using PostgreSQL via Grove ORM.

func New

func New(db *grove.DB) *Store

New creates a new PostgreSQL store backed by Grove ORM.

func (*Store) AdvanceSubscriptionPeriod

func (s *Store) AdvanceSubscriptionPeriod(ctx context.Context, subID id.SubscriptionID, from, start, end, at time.Time) (bool, error)

func (*Store) Aggregate

func (s *Store) Aggregate(ctx context.Context, tenantID, appID, featureKey string, period plan.Period) (int64, error)

func (*Store) AggregateMulti

func (s *Store) AggregateMulti(ctx context.Context, tenantID, appID string, featureKeys []string, period plan.Period) (map[string]int64, error)

func (*Store) ApplyCoupon

func (s *Store) ApplyCoupon(ctx context.Context, subID id.SubscriptionID, couponID id.CouponID) error

ApplyCoupon is a low-level operation kept for callers and tests that need it separately. Engine code redeems through RedeemCoupon, which records the application and increments the redemption count as one unit.

func (*Store) ArchiveFeature

func (s *Store) ArchiveFeature(ctx context.Context, featureID id.FeatureID) error

func (*Store) ArchivePlan

func (s *Store) ArchivePlan(ctx context.Context, planID id.PlanID) error

func (*Store) CancelSubscription

func (s *Store) CancelSubscription(ctx context.Context, subID id.SubscriptionID, immediately bool) (time.Time, error)

func (*Store) ChangeSubscriptionPlan

func (s *Store) ChangeSubscriptionPlan(ctx context.Context, subID id.SubscriptionID, planID id.PlanID, quantity map[string]int64) (bool, error)

func (*Store) Close

func (s *Store) Close() error

Close closes the database connection.

func (*Store) CreateCoupon

func (s *Store) CreateCoupon(ctx context.Context, c *coupon.Coupon) error

func (*Store) CreateFeature

func (s *Store) CreateFeature(ctx context.Context, f *feature.Feature) error

func (*Store) CreateInvoice

func (s *Store) CreateInvoice(ctx context.Context, inv *invoice.Invoice) error

func (*Store) CreatePlan

func (s *Store) CreatePlan(ctx context.Context, p *plan.Plan) error

func (*Store) CreateSubscription

func (s *Store) CreateSubscription(ctx context.Context, sub *subscription.Subscription) error

func (*Store) DB

func (s *Store) DB() *grove.DB

DB returns the underlying grove database for direct access.

func (*Store) DeleteCoupon

func (s *Store) DeleteCoupon(ctx context.Context, couponID id.CouponID) error

func (*Store) DeleteFeature

func (s *Store) DeleteFeature(ctx context.Context, featureID id.FeatureID) error

func (*Store) DeletePlan

func (s *Store) DeletePlan(ctx context.Context, planID id.PlanID) error

func (*Store) EnactSubscriptionCancel

func (s *Store) EnactSubscriptionCancel(ctx context.Context, subID id.SubscriptionID, at time.Time) (bool, error)

func (*Store) EndSubscriptionTrial

func (s *Store) EndSubscriptionTrial(ctx context.Context, subID id.SubscriptionID, at time.Time) (bool, error)

func (*Store) GetActiveSubscription

func (s *Store) GetActiveSubscription(ctx context.Context, tenantID, appID string) (*subscription.Subscription, error)

func (*Store) GetCached

func (s *Store) GetCached(ctx context.Context, tenantID, appID, featureKey string) (*entitlement.Result, error)

func (*Store) GetCoupon

func (s *Store) GetCoupon(ctx context.Context, code, appID string) (*coupon.Coupon, error)

func (*Store) GetCouponByID

func (s *Store) GetCouponByID(ctx context.Context, couponID id.CouponID) (*coupon.Coupon, error)

func (*Store) GetFeature

func (s *Store) GetFeature(ctx context.Context, featureID id.FeatureID) (*feature.Feature, error)

func (*Store) GetFeatureByKey

func (s *Store) GetFeatureByKey(ctx context.Context, key, appID string) (*feature.Feature, error)

func (*Store) GetInvoice

func (s *Store) GetInvoice(ctx context.Context, invID id.InvoiceID) (*invoice.Invoice, error)

func (*Store) GetInvoiceByPeriod

func (s *Store) GetInvoiceByPeriod(ctx context.Context, tenantID, appID string, periodStart, periodEnd time.Time) (*invoice.Invoice, error)

func (*Store) GetPlan

func (s *Store) GetPlan(ctx context.Context, planID id.PlanID) (*plan.Plan, error)

func (*Store) GetPlanBySlug

func (s *Store) GetPlanBySlug(ctx context.Context, slug, appID string) (*plan.Plan, error)

func (*Store) GetSubscription

func (s *Store) GetSubscription(ctx context.Context, subID id.SubscriptionID) (*subscription.Subscription, error)

func (*Store) IncrementCouponRedemptions

func (s *Store) IncrementCouponRedemptions(ctx context.Context, couponID id.CouponID) error

IncrementCouponRedemptions is a low-level operation kept for callers and tests that need it separately. Engine code redeems through RedeemCoupon, which increments the count and records the application as one unit.

func (*Store) IngestBatch

func (s *Store) IngestBatch(ctx context.Context, events []*meter.UsageEvent) error

func (*Store) Invalidate

func (s *Store) Invalidate(ctx context.Context, tenantID, appID string) error

func (*Store) InvalidateFeature

func (s *Store) InvalidateFeature(ctx context.Context, tenantID, appID, featureKey string) error

func (*Store) ListAppliedCoupons

func (s *Store) ListAppliedCoupons(ctx context.Context, subID id.SubscriptionID) ([]*coupon.Coupon, error)

func (*Store) ListCoupons

func (s *Store) ListCoupons(ctx context.Context, appID string, opts coupon.ListOpts) ([]*coupon.Coupon, error)

func (*Store) ListDueSubscriptions

func (s *Store) ListDueSubscriptions(ctx context.Context, opts subscription.DueOpts) ([]*subscription.Subscription, error)

func (*Store) ListFeatures

func (s *Store) ListFeatures(ctx context.Context, appID string, opts feature.ListOpts) ([]*feature.Feature, error)

func (*Store) ListGlobalFeatures

func (s *Store) ListGlobalFeatures(ctx context.Context, opts feature.ListOpts) ([]*feature.Feature, error)

func (*Store) ListInvoices

func (s *Store) ListInvoices(ctx context.Context, tenantID, appID string, opts invoice.ListOpts) ([]*invoice.Invoice, error)

func (*Store) ListOverdueInvoices

func (s *Store) ListOverdueInvoices(ctx context.Context, opts invoice.OverdueOpts) ([]*invoice.Invoice, error)

func (*Store) ListPendingInvoices

func (s *Store) ListPendingInvoices(ctx context.Context, appID string) ([]*invoice.Invoice, error)

func (*Store) ListPlans

func (s *Store) ListPlans(ctx context.Context, appID string, opts plan.ListOpts) ([]*plan.Plan, error)

func (*Store) ListSubscriptions

func (s *Store) ListSubscriptions(ctx context.Context, tenantID, appID string, opts subscription.ListOpts) ([]*subscription.Subscription, error)

func (*Store) MarkInvoicePaid

func (s *Store) MarkInvoicePaid(ctx context.Context, invID id.InvoiceID, paidAt time.Time, paymentRef string) error

func (*Store) MarkInvoicePastDue

func (s *Store) MarkInvoicePastDue(ctx context.Context, invID id.InvoiceID, at time.Time) (bool, error)

func (*Store) MarkInvoiceVoided

func (s *Store) MarkInvoiceVoided(ctx context.Context, invID id.InvoiceID, reason string) error

func (*Store) Migrate

func (s *Store) Migrate(ctx context.Context) error

Migrate creates the required tables and indexes using the grove orchestrator.

func (*Store) PauseSubscription

func (s *Store) PauseSubscription(ctx context.Context, subID id.SubscriptionID, at time.Time) (bool, error)

func (*Store) Ping

func (s *Store) Ping(ctx context.Context) error

Ping checks database connectivity.

func (*Store) PurgeUsage

func (s *Store) PurgeUsage(ctx context.Context, before time.Time) (int64, error)

func (*Store) QueryUsage

func (s *Store) QueryUsage(ctx context.Context, tenantID, appID string, opts meter.QueryOpts) ([]*meter.UsageEvent, error)

func (*Store) RedeemCoupon

func (s *Store) RedeemCoupon(ctx context.Context, subID id.SubscriptionID, couponID id.CouponID) error

RedeemCoupon records a coupon's application to a subscription and increments its redemption count in one transaction, committing only when both writes land. The cap (MaxRedemptions) is enforced by a conditional UPDATE - `times_redeemed = times_redeemed + 1 WHERE id = ? AND (max_redemptions <= 0 OR times_redeemed < max_redemptions)` - rather than a read of TimesRedeemed followed by a separate write, so two concurrent transactions racing the same coupon toward its cap cannot both read the count before either writes it: Postgres takes a row lock on the first UPDATE to reach the row and blocks the second until it commits, at which point the second's WHERE re-evaluates against the already-incremented count under read-committed semantics.

The INSERT of the application row is the FIRST statement in the transaction, matching sqlite's RedeemCoupon (the two are kept structurally identical on purpose). Postgres itself has no equivalent to sqlite's lock-upgrade BUSY, but opening with a read here would still mean two different statement shapes to reason about across backends for no benefit, and the FK on ledger_coupon_applications.coupon_id already gives this insert a cheap, correct way to catch an unknown coupon without a SELECT: it fails with a 23503 foreign-key violation, mapped below to ErrCouponNotFound.

Unknown coupon and exhausted cap share one signal - the conditional UPDATE affects zero rows - and are told apart only if that happens: on postgres this is normally unreachable for an unknown coupon (the FK above already refused the insert), so the existence check here is a defensive fallback for the case where the coupon was deleted between this transaction's insert and its update, not the primary way unknown coupons are caught.

func (*Store) ResumeSubscription

func (s *Store) ResumeSubscription(ctx context.Context, subID id.SubscriptionID, r subscription.Resume) (bool, error)

func (*Store) SetCached

func (s *Store) SetCached(ctx context.Context, tenantID, appID, featureKey string, result *entitlement.Result, ttl time.Duration) error

func (*Store) SetInvoiceProvider

func (s *Store) SetInvoiceProvider(ctx context.Context, invID id.InvoiceID, providerID, providerName string) error

func (*Store) SetSubscriptionProvider

func (s *Store) SetSubscriptionProvider(ctx context.Context, subID id.SubscriptionID, providerID, providerName string) error

func (*Store) UpdateCoupon

func (s *Store) UpdateCoupon(ctx context.Context, c *coupon.Coupon) error

func (*Store) UpdateFeature

func (s *Store) UpdateFeature(ctx context.Context, f *feature.Feature) error

func (*Store) UpdateInvoice

func (s *Store) UpdateInvoice(ctx context.Context, inv *invoice.Invoice) error

func (*Store) UpdatePlan

func (s *Store) UpdatePlan(ctx context.Context, p *plan.Plan) error

func (*Store) UpdateSubscription

func (s *Store) UpdateSubscription(ctx context.Context, sub *subscription.Subscription) error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL