Skip to content

Commit 25e6fd5

Browse files
committed
refactor: enhance filtering logic in store methods and add Store method to Ledger
1 parent a29fce4 commit 25e6fd5

9 files changed

Lines changed: 223 additions & 94 deletions

File tree

dashboard/contributor.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -602,17 +602,19 @@ func (c *Contributor) renderFeatures(ctx context.Context, params contributor.Par
602602
return nil, fmt.Errorf("dashboard: render features: %w", err)
603603
}
604604

605-
// Also include global features.
606-
globalFeatures, err := c.store.ListGlobalFeatures(ctx, opts)
607-
if err != nil {
608-
globalFeatures = nil
605+
// When appID is set, also include global features.
606+
// When appID is empty, ListFeatures already returns all features.
607+
allFeatures := features
608+
if c.appID != "" {
609+
globalFeatures, err := c.store.ListGlobalFeatures(ctx, opts)
610+
if err != nil {
611+
globalFeatures = nil
612+
}
613+
allFeatures = make([]*feature.Feature, 0, len(features)+len(globalFeatures))
614+
allFeatures = append(allFeatures, features...)
615+
allFeatures = append(allFeatures, globalFeatures...)
609616
}
610617

611-
// Merge: app-scoped first, then global.
612-
allFeatures := make([]*feature.Feature, 0, len(features)+len(globalFeatures))
613-
allFeatures = append(allFeatures, features...)
614-
allFeatures = append(allFeatures, globalFeatures...)
615-
616618
return pages.FeaturesPage(pages.FeatureListData{
617619
Features: allFeatures,
618620
AppID: c.appID,

go.mod

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ module github.com/xraph/ledger
33
go 1.25.7
44

55
require (
6-
github.com/a-h/templ v0.3.977
7-
github.com/xraph/forge v1.3.1
8-
github.com/xraph/forgeui v1.3.0
9-
github.com/xraph/go-utils v1.0.0
10-
github.com/xraph/grove v1.3.1
11-
github.com/xraph/grove/drivers/mongodriver v1.3.1
12-
github.com/xraph/grove/drivers/pgdriver v1.3.1
13-
github.com/xraph/grove/drivers/sqlitedriver v1.3.1
6+
github.com/a-h/templ v0.3.1001
7+
github.com/xraph/forge v1.4.0
8+
github.com/xraph/forgeui v1.4.0
9+
github.com/xraph/go-utils v1.1.0
10+
github.com/xraph/grove v1.4.0
11+
github.com/xraph/grove/drivers/mongodriver v1.4.0
12+
github.com/xraph/grove/drivers/pgdriver v1.4.0
13+
github.com/xraph/grove/drivers/sqlitedriver v1.4.0
1414
github.com/xraph/vessel v1.0.0
1515
go.jetify.com/typeid/v2 v2.0.0-alpha.3
1616
go.mongodb.org/mongo-driver/v2 v2.5.0
@@ -108,7 +108,7 @@ require (
108108
golang.org/x/sync v0.19.0 // indirect
109109
golang.org/x/sys v0.41.0 // indirect
110110
golang.org/x/term v0.39.0 // indirect
111-
golang.org/x/text v0.33.0 // indirect
111+
golang.org/x/text v0.34.0 // indirect
112112
golang.org/x/time v0.12.0 // indirect
113113
google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 // indirect
114114
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 // indirect

go.sum

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1
55
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
66
github.com/Oudwins/tailwind-merge-go v0.2.1 h1:jxRaEqGtwwwF48UuFIQ8g8XT7YSualNuGzCvQ89nPFE=
77
github.com/Oudwins/tailwind-merge-go v0.2.1/go.mod h1:kkZodgOPvZQ8f7SIrlWkG/w1g9JTbtnptnePIh3V72U=
8-
github.com/a-h/templ v0.3.977 h1:kiKAPXTZE2Iaf8JbtM21r54A8bCNsncrfnokZZSrSDg=
9-
github.com/a-h/templ v0.3.977/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo=
8+
github.com/a-h/templ v0.3.1001 h1:yHDTgexACdJttyiyamcTHXr2QkIeVF1MukLy44EAhMY=
9+
github.com/a-h/templ v0.3.1001/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo=
1010
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
1111
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
1212
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -306,20 +306,20 @@ github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6
306306
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
307307
github.com/xraph/confy v0.1.0 h1:dAdI/ShnkU5PEXVsfR86swoWj6XjJ37BdPQpBIUmg9M=
308308
github.com/xraph/confy v0.1.0/go.mod h1:/uhVfKibPR+kn7MI9LkVVekk84NP0sxsKZ9sFQoQ5Kc=
309-
github.com/xraph/forge v1.3.1 h1:DX8uqNAFNeY+/L/o/PosJIHYSE0pcGzfScxB1Xgl0mM=
310-
github.com/xraph/forge v1.3.1/go.mod h1:SL+lSzFEd9sDw+LTVUeMsVLlWhZM83LMunP2yf6Dm28=
311-
github.com/xraph/forgeui v1.3.0 h1:HPS6+7fndy0qMkD1tB1QNydTOAqQ7oXOTi30+TlXOok=
312-
github.com/xraph/forgeui v1.3.0/go.mod h1:2oXAltVMFHJJG0OmXNzcA/BAEE+8L36LGTlkkDgaPpA=
313-
github.com/xraph/go-utils v1.0.0 h1:P1jOvtDlC5xZyGtnIhypFfPUBgpfyrwESY4TK4P2I5g=
314-
github.com/xraph/go-utils v1.0.0/go.mod h1:yp+PD9dXSA7tA9Pxmuveg5E7Ht1iHIVov8yMvanMG7U=
315-
github.com/xraph/grove v1.3.1 h1:IqM+Ynr4pNwPTUXDxhw7O3n0hkT4YEq/096om5V7pN8=
316-
github.com/xraph/grove v1.3.1/go.mod h1:9G6mvF6KO+AvlaaXQoBevlxiWs/n2p/EhBVNgdYR0FA=
317-
github.com/xraph/grove/drivers/mongodriver v1.3.1 h1:vIAU+oJeAPXqY71w1qN35ts0xMiBUyqbsinbu5u9KfQ=
318-
github.com/xraph/grove/drivers/mongodriver v1.3.1/go.mod h1:P+msnEenoXJnNWFh/wWi/EzAqjsdscq3EthcCqSDwaY=
319-
github.com/xraph/grove/drivers/pgdriver v1.3.1 h1:Mw60dFmOVhenclJjRTlt32Q4coayPLoU52NNS9gnHgM=
320-
github.com/xraph/grove/drivers/pgdriver v1.3.1/go.mod h1:ogSHbP1rbZO/5UnfYWhBzrRlEtwH4V4T0hrl/8GlTzU=
321-
github.com/xraph/grove/drivers/sqlitedriver v1.3.1 h1:4G5XWm/M2VqMB0WtHlXSXT1lH+YoXJ+RuvwB94gwxvU=
322-
github.com/xraph/grove/drivers/sqlitedriver v1.3.1/go.mod h1:AIyBtYUgMrtzrvtB6sHU/EyEEeRf/TPrgDGDV7uKpOQ=
309+
github.com/xraph/forge v1.4.0 h1:+7NjO2iz9+JGxwDFS3hfNp73/JiqHlXYxWN5nD3WqbM=
310+
github.com/xraph/forge v1.4.0/go.mod h1:M+aj9K6XOBkYvVWnwESqCuFcn8/P6lu0C1tknBqz3Mg=
311+
github.com/xraph/forgeui v1.4.0 h1:RhpRbecimGCSDf0XQnJhl5PmQjbxrF5M2PGEk6F60sg=
312+
github.com/xraph/forgeui v1.4.0/go.mod h1:rH/+wb1tt2pXSHotWAvoP+Lt846xlIjuwPDSpS5K5mw=
313+
github.com/xraph/go-utils v1.1.0 h1:bPO4C/mwm0I5ZZa3RxbwUqKhy3Vnxvm3s98vmX8CrjY=
314+
github.com/xraph/go-utils v1.1.0/go.mod h1:tZN4SuGy9otCo6dETp7Cvkgyiy0BvaJaZbTBv4Euvo4=
315+
github.com/xraph/grove v1.4.0 h1:7rv/Ixhp7swZOReax3g/kEVv13p02YkulFmGjv2HLOg=
316+
github.com/xraph/grove v1.4.0/go.mod h1:3vrjpafTi3VA3OD05xIHMRsfqlcZW34+/tOJqzlUvv8=
317+
github.com/xraph/grove/drivers/mongodriver v1.4.0 h1:tfLQBBUoN3l7K4pr6EmwepgSYRB+zVmP9XGjwn+h22U=
318+
github.com/xraph/grove/drivers/mongodriver v1.4.0/go.mod h1:46El0w2/vGeqTTWYTfq9I0sXXxaLBiOJFaXPEEBVwAY=
319+
github.com/xraph/grove/drivers/pgdriver v1.4.0 h1:Ua3XSdVieVT9Ia2WY0kkpTd+QTqhl8GFb8uV6JhZkqE=
320+
github.com/xraph/grove/drivers/pgdriver v1.4.0/go.mod h1:aXris8DoBvJwGTpnF2kMC50aBwpxv/e+4mGMRFpC9B0=
321+
github.com/xraph/grove/drivers/sqlitedriver v1.4.0 h1:kDK5nufN1+pRy7fSk+7VcCxgLjl5azCG8Tgd7c+vGYs=
322+
github.com/xraph/grove/drivers/sqlitedriver v1.4.0/go.mod h1:YwhMU+qclOkK0pRrbfvyuhGRU8eREY5jEfViI2FjqFk=
323323
github.com/xraph/vessel v1.0.0 h1:n2q30d0OGPENpFfmOUgEuS99Y+X6b6WTfzdOHiE4Ds0=
324324
github.com/xraph/vessel v1.0.0/go.mod h1:quT3UWDXZF0RLL34H3ijXP9kVnh2pdfnn0f2s3ezChA=
325325
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
@@ -427,8 +427,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
427427
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
428428
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
429429
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
430-
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
431-
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
430+
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
431+
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
432432
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
433433
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
434434
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

ledger.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ func WithEntitlementCacheTTL(ttl time.Duration) Option {
9292
}
9393
}
9494

95+
// Store returns the underlying ledger store.
96+
func (l *Ledger) Store() store.Store { return l.store }
97+
9598
// Start begins background workers.
9699
func (l *Ledger) Start(ctx context.Context) error {
97100
// Migrate database

store/memory/store.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func (s *Store) ListPlans(_ context.Context, appID string, opts plan.ListOpts) (
9696

9797
result := make([]*plan.Plan, 0)
9898
for _, p := range s.plans {
99-
if p.AppID == appID {
99+
if appID == "" || p.AppID == appID {
100100
if opts.Status == "" || p.Status == opts.Status {
101101
result = append(result, p)
102102
}
@@ -187,7 +187,7 @@ func (s *Store) ListSubscriptions(_ context.Context, tenantID, appID string, opt
187187

188188
result := make([]*subscription.Subscription, 0)
189189
for _, sub := range s.subscriptions {
190-
if sub.TenantID == tenantID && sub.AppID == appID {
190+
if (tenantID == "" || sub.TenantID == tenantID) && (appID == "" || sub.AppID == appID) {
191191
if opts.Status == "" || sub.Status == opts.Status {
192192
result = append(result, sub)
193193
}
@@ -278,7 +278,7 @@ func (s *Store) QueryUsage(_ context.Context, tenantID, appID string, opts meter
278278
result := make([]*meter.UsageEvent, 0)
279279
for i := range s.usageEvents {
280280
e := &s.usageEvents[i]
281-
if e.TenantID == tenantID && e.AppID == appID {
281+
if (tenantID == "" || e.TenantID == tenantID) && (appID == "" || e.AppID == appID) {
282282
if opts.FeatureKey == "" || e.FeatureKey == opts.FeatureKey {
283283
if (opts.Start.IsZero() || e.Timestamp.After(opts.Start)) &&
284284
(opts.End.IsZero() || e.Timestamp.Before(opts.End)) {
@@ -382,7 +382,7 @@ func (s *Store) ListInvoices(_ context.Context, tenantID, appID string, opts inv
382382

383383
result := make([]*invoice.Invoice, 0)
384384
for _, inv := range s.invoices {
385-
if inv.TenantID == tenantID && inv.AppID == appID {
385+
if (tenantID == "" || inv.TenantID == tenantID) && (appID == "" || inv.AppID == appID) {
386386
if opts.Status == "" || inv.Status == opts.Status {
387387
result = append(result, inv)
388388
}
@@ -418,7 +418,7 @@ func (s *Store) ListPendingInvoices(_ context.Context, appID string) ([]*invoice
418418

419419
result := make([]*invoice.Invoice, 0)
420420
for _, inv := range s.invoices {
421-
if inv.AppID == appID && inv.Status == invoice.StatusPending {
421+
if (appID == "" || inv.AppID == appID) && inv.Status == invoice.StatusPending {
422422
result = append(result, inv)
423423
}
424424
}
@@ -491,7 +491,7 @@ func (s *Store) ListCoupons(_ context.Context, appID string, opts coupon.ListOpt
491491
now := time.Now()
492492

493493
for _, c := range s.coupons {
494-
if c.AppID == appID {
494+
if appID == "" || c.AppID == appID {
495495
if opts.Active {
496496
if (c.ValidFrom == nil || now.After(*c.ValidFrom)) &&
497497
(c.ValidUntil == nil || now.Before(*c.ValidUntil)) {
@@ -567,7 +567,7 @@ func (s *Store) ListFeatures(_ context.Context, appID string, opts feature.ListO
567567

568568
result := make([]*feature.Feature, 0)
569569
for _, f := range s.features {
570-
if f.AppID == appID {
570+
if appID == "" || f.AppID == appID {
571571
if opts.Status == "" || f.Status == opts.Status {
572572
result = append(result, f)
573573
}

store/mongo/store.go

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,10 @@ func (s *Store) GetPlanBySlug(ctx context.Context, slug, appID string) (*plan.Pl
124124
func (s *Store) ListPlans(ctx context.Context, appID string, opts plan.ListOpts) ([]*plan.Plan, error) {
125125
var models []planModel
126126

127-
filter := bson.M{"app_id": appID}
127+
filter := bson.M{}
128+
if appID != "" {
129+
filter["app_id"] = appID
130+
}
128131
if opts.Status != "" {
129132
filter["status"] = string(opts.Status)
130133
}
@@ -248,7 +251,13 @@ func (s *Store) GetActiveSubscription(ctx context.Context, tenantID, appID strin
248251
func (s *Store) ListSubscriptions(ctx context.Context, tenantID, appID string, opts subscription.ListOpts) ([]*subscription.Subscription, error) {
249252
var models []subscriptionModel
250253

251-
filter := bson.M{"tenant_id": tenantID, "app_id": appID}
254+
filter := bson.M{}
255+
if tenantID != "" {
256+
filter["tenant_id"] = tenantID
257+
}
258+
if appID != "" {
259+
filter["app_id"] = appID
260+
}
252261
if opts.Status != "" {
253262
filter["status"] = string(opts.Status)
254263
}
@@ -389,7 +398,13 @@ func (s *Store) AggregateMulti(ctx context.Context, tenantID, appID string, feat
389398
func (s *Store) QueryUsage(ctx context.Context, tenantID, appID string, opts meter.QueryOpts) ([]*meter.UsageEvent, error) {
390399
var models []usageEventModel
391400

392-
filter := bson.M{"tenant_id": tenantID, "app_id": appID}
401+
filter := bson.M{}
402+
if tenantID != "" {
403+
filter["tenant_id"] = tenantID
404+
}
405+
if appID != "" {
406+
filter["app_id"] = appID
407+
}
393408
if opts.FeatureKey != "" {
394409
filter["feature_key"] = opts.FeatureKey
395410
}
@@ -544,7 +559,13 @@ func (s *Store) GetInvoice(ctx context.Context, invID id.InvoiceID) (*invoice.In
544559
func (s *Store) ListInvoices(ctx context.Context, tenantID, appID string, opts invoice.ListOpts) ([]*invoice.Invoice, error) {
545560
var models []invoiceModel
546561

547-
filter := bson.M{"tenant_id": tenantID, "app_id": appID}
562+
filter := bson.M{}
563+
if tenantID != "" {
564+
filter["tenant_id"] = tenantID
565+
}
566+
if appID != "" {
567+
filter["app_id"] = appID
568+
}
548569
if opts.Status != "" {
549570
filter["status"] = string(opts.Status)
550571
}
@@ -616,8 +637,13 @@ func (s *Store) GetInvoiceByPeriod(ctx context.Context, tenantID, appID string,
616637
func (s *Store) ListPendingInvoices(ctx context.Context, appID string) ([]*invoice.Invoice, error) {
617638
var models []invoiceModel
618639

640+
filter := bson.M{"status": string(invoice.StatusPending)}
641+
if appID != "" {
642+
filter["app_id"] = appID
643+
}
644+
619645
err := s.mdb.NewFind(&models).
620-
Filter(bson.M{"app_id": appID, "status": string(invoice.StatusPending)}).
646+
Filter(filter).
621647
Sort(bson.D{{Key: "created_at", Value: -1}}).
622648
Scan(ctx)
623649
if err != nil {
@@ -713,7 +739,10 @@ func (s *Store) GetCouponByID(ctx context.Context, couponID id.CouponID) (*coupo
713739
func (s *Store) ListCoupons(ctx context.Context, appID string, opts coupon.ListOpts) ([]*coupon.Coupon, error) {
714740
var models []couponModel
715741

716-
filter := bson.M{"app_id": appID}
742+
filter := bson.M{}
743+
if appID != "" {
744+
filter["app_id"] = appID
745+
}
717746
if opts.Active {
718747
t := time.Now().UTC()
719748
filter["$and"] = bson.A{
@@ -827,7 +856,10 @@ func (s *Store) GetFeatureByKey(ctx context.Context, key, appID string) (*featur
827856
func (s *Store) ListFeatures(ctx context.Context, appID string, opts feature.ListOpts) ([]*feature.Feature, error) {
828857
var models []featureCatalogModel
829858

830-
filter := bson.M{"app_id": appID}
859+
filter := bson.M{}
860+
if appID != "" {
861+
filter["app_id"] = appID
862+
}
831863
if opts.Status != "" {
832864
filter["status"] = string(opts.Status)
833865
}

0 commit comments

Comments
 (0)