260 lines
6.4 KiB
Go
260 lines
6.4 KiB
Go
package reports
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"slices"
|
|
"time"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
|
|
"ruben/inventory2/consts"
|
|
"ruben/inventory2/domains/accounts"
|
|
"ruben/inventory2/logging"
|
|
)
|
|
|
|
//go:generate concurry -s Store
|
|
|
|
type (
|
|
Store struct {
|
|
log *logging.Logger
|
|
db *pgxpool.Pool
|
|
accts *accounts.Store
|
|
}
|
|
)
|
|
|
|
func NewStore(logger *logging.Logger, db *pgxpool.Pool, accts *accounts.Store) *Store {
|
|
return &Store{
|
|
log: logger,
|
|
db: db,
|
|
accts: accts,
|
|
}
|
|
}
|
|
|
|
func (db *Store) WithContext(ctx context.Context) *StoreWithContext {
|
|
return NewStoreWithContext(ctx, db)
|
|
}
|
|
|
|
// TODO: prefix all these names with 'mock' since they're all mock stuff
|
|
|
|
type (
|
|
ListingCountsOverTimeReport struct {
|
|
AccountID int64
|
|
Platform accounts.Platform
|
|
ShopID string
|
|
ListingID string
|
|
Counts []ListingCountAtTime
|
|
}
|
|
|
|
ListingCountAtTime struct {
|
|
EventTimestamp *time.Time
|
|
Count int64
|
|
}
|
|
)
|
|
|
|
func (r ListingCountsOverTimeReport) MaxCount() ListingCountAtTime {
|
|
if len(r.Counts) == 0 {
|
|
return ListingCountAtTime{}
|
|
}
|
|
return slices.MaxFunc(r.Counts, func(a, b ListingCountAtTime) int {
|
|
return int(a.Count - b.Count)
|
|
})
|
|
}
|
|
|
|
func (r ListingCountsOverTimeReport) MinCount() ListingCountAtTime {
|
|
if len(r.Counts) == 0 {
|
|
return ListingCountAtTime{}
|
|
}
|
|
return slices.MinFunc(r.Counts, func(a, b ListingCountAtTime) int {
|
|
return int(a.Count - b.Count)
|
|
})
|
|
}
|
|
|
|
func (db *Store) GetListingCountsReport(ctx context.Context, acctID int64, platform accounts.Platform, shopID, listingID string) (*ListingCountsOverTimeReport, error) {
|
|
counts, err := db.GetListingCountsOverTime(ctx, acctID, platform, shopID, listingID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ListingCountsOverTimeReport{
|
|
AccountID: acctID,
|
|
Platform: platform,
|
|
ShopID: shopID,
|
|
ListingID: listingID,
|
|
Counts: counts,
|
|
}, nil
|
|
}
|
|
|
|
func (db *Store) GetListingCountsOverTime(ctx context.Context, acctID int64, platform accounts.Platform, shopID, listingID string) ([]ListingCountAtTime, error) {
|
|
info, ok := getMockShopSchemaInfo(platform)
|
|
if !ok {
|
|
return nil, consts.ErrNotFound
|
|
}
|
|
|
|
var counts []ListingCountAtTime
|
|
|
|
err := pgx.BeginTxFunc(ctx, db.db, pgx.TxOptions{
|
|
AccessMode: pgx.ReadOnly,
|
|
}, func(tx pgx.Tx) error {
|
|
rows, err := tx.Query(
|
|
ctx,
|
|
fmt.Sprintf(
|
|
`
|
|
SELECT
|
|
1
|
|
FROM
|
|
%s
|
|
WHERE
|
|
shop_id = @shop_id
|
|
AND listing_id = @listing_id
|
|
`,
|
|
info.listingsTable,
|
|
),
|
|
pgx.NamedArgs{
|
|
"shop_id": shopID,
|
|
"listing_id": listingID,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to perform query to check the existing of the listing: %w", err)
|
|
}
|
|
|
|
if _, err := pgx.CollectExactlyOneRow(rows, pgx.RowTo[int]); err != nil {
|
|
return fmt.Errorf("listing not found: %w", consts.ErrNotFound)
|
|
}
|
|
|
|
rows, err = tx.Query(
|
|
ctx,
|
|
fmt.Sprintf(
|
|
`
|
|
SELECT
|
|
event_timestamp AS eventTimestamp,
|
|
"count"
|
|
FROM
|
|
%s
|
|
WHERE
|
|
shop_id = @shop_id
|
|
AND listing_id = @listing_id
|
|
`,
|
|
info.listingCountsView,
|
|
),
|
|
pgx.NamedArgs{
|
|
"shop_id": shopID,
|
|
"listing_id": listingID,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to perform query: %w", err)
|
|
}
|
|
|
|
if counts, err = pgx.CollectRows(rows, pgx.RowToStructByNameLax[ListingCountAtTime]); err != nil {
|
|
return fmt.Errorf("failed to scan rows: %w", err)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
return counts, err
|
|
}
|
|
|
|
type mockShopSchemaInfo struct {
|
|
platform accounts.Platform
|
|
shopTable string
|
|
listingsTable string
|
|
listingCountsView string
|
|
}
|
|
|
|
func getMockShopSchemaInfo(platform accounts.Platform) (mockShopSchemaInfo, bool) {
|
|
for _, in := range getAllMockShopSchemaInfos() {
|
|
if in.platform == platform {
|
|
return in, true
|
|
}
|
|
}
|
|
|
|
return mockShopSchemaInfo{}, false
|
|
}
|
|
|
|
func getAllMockShopSchemaInfos() []mockShopSchemaInfo {
|
|
return []mockShopSchemaInfo{
|
|
{
|
|
platform: accounts.Amazon,
|
|
shopTable: "mock.shop_amazon",
|
|
listingsTable: "mock.shop_amazon_listings",
|
|
listingCountsView: "mock.shop_amazon_listing_counts",
|
|
},
|
|
{
|
|
platform: accounts.BigCartel,
|
|
shopTable: "mock.shop_big_cartel",
|
|
listingsTable: "mock.shop_big_cartel_listings",
|
|
listingCountsView: "mock.shop_big_cartel_listing_counts",
|
|
},
|
|
{
|
|
platform: accounts.Ebay,
|
|
shopTable: "mock.shop_ebay",
|
|
listingsTable: "mock.shop_ebay_listings",
|
|
listingCountsView: "mock.shop_ebay_listing_counts",
|
|
},
|
|
{
|
|
platform: accounts.Ecwid,
|
|
shopTable: "mock.shop_ecwid",
|
|
listingsTable: "mock.shop_ecwid_listings",
|
|
listingCountsView: "mock.shop_ecwid_listing_counts",
|
|
},
|
|
{
|
|
platform: accounts.Etsy,
|
|
shopTable: "mock.shop_etsy",
|
|
listingsTable: "mock.shop_etsy_listings",
|
|
listingCountsView: "mock.shop_etsy_listing_counts",
|
|
},
|
|
{
|
|
platform: accounts.Shopify,
|
|
shopTable: "mock.shop_shopify",
|
|
listingsTable: "mock.shop_shopify_listings",
|
|
listingCountsView: "mock.shop_shopify_listing_counts",
|
|
},
|
|
{
|
|
platform: accounts.SquareOnline,
|
|
shopTable: "mock.shop_square_online",
|
|
listingsTable: "mock.shop_square_online_listings",
|
|
listingCountsView: "mock.shop_square_online_listing_counts",
|
|
},
|
|
{
|
|
platform: accounts.Squarespace,
|
|
shopTable: "mock.shop_squarespace",
|
|
listingsTable: "mock.shop_squarespace_listings",
|
|
listingCountsView: "mock.shop_squarespace_listing_counts",
|
|
},
|
|
{
|
|
platform: accounts.Tiktok,
|
|
shopTable: "mock.shop_tiktok",
|
|
listingsTable: "mock.shop_tiktok_listings",
|
|
listingCountsView: "mock.shop_tiktok_listing_counts",
|
|
},
|
|
{
|
|
platform: accounts.WalmartMarketplace,
|
|
shopTable: "mock.shop_walmart_marketplace",
|
|
listingsTable: "mock.shop_walmart_marketplace_listings",
|
|
listingCountsView: "mock.shop_walmart_marketplace_listing_counts",
|
|
},
|
|
{
|
|
platform: accounts.Wix,
|
|
shopTable: "mock.shop_wix",
|
|
listingsTable: "mock.shop_wix_listings",
|
|
listingCountsView: "mock.shop_wix_listing_counts",
|
|
},
|
|
{
|
|
platform: accounts.WooCommerce,
|
|
shopTable: "mock.shop_woo_commerce",
|
|
listingsTable: "mock.shop_woo_commerce_listings",
|
|
listingCountsView: "mock.shop_woo_commerce_listing_counts",
|
|
},
|
|
{
|
|
platform: accounts.Zoho,
|
|
shopTable: "mock.shop_zoho",
|
|
listingsTable: "mock.shop_zoho_listings",
|
|
listingCountsView: "mock.shop_zoho_listing_counts",
|
|
},
|
|
}
|
|
}
|