mock shop sync group listing draft page

This commit is contained in:
2026-02-08 12:31:10 -07:00
parent e3b2dd3377
commit b155280081
19 changed files with 1519 additions and 166 deletions
+117
View File
@@ -277,6 +277,63 @@ func (db *Store) GetShops(ctx context.Context, acctID int64) ([]AccountShop, err
return shops, nil
}
func (db *Store) GetMockShops(ctx context.Context, acctID int64) ([]AccountShop, error) {
infos := getAllMockShopSchemaInfos()
lists := make([][]AccountShop, len(infos))
numShops := 0
for i, in := range infos {
rows, err := db.db.Query(
ctx,
fmt.Sprintf(
`
SELECT
shop_id,
name
FROM
%s
WHERE
account_id = @account_id
`,
in.shopTable,
),
pgx.NamedArgs{
"account_id": acctID,
},
)
if err != nil {
return nil, fmt.Errorf("failed to perform query: %w", err)
}
vs, err := pgx.CollectRows(rows, pgx.RowToStructByNameLax[struct {
Shop_id string
Name string
}])
if err != nil {
return nil, fmt.Errorf("failed to scan rows: %w", err)
}
list := make([]AccountShop, len(vs))
for i, v := range vs {
list[i] = AccountShop{
AccountShopIDs: NewAccountIDs(acctID).
ShopID(in.platform, v.Shop_id),
Name: v.Name,
}
}
lists[i] = list
numShops += len(list)
}
shops := make([]AccountShop, 0, numShops)
for _, list := range lists {
shops = append(shops, list...)
}
return shops, nil
}
func (db *Store) GetListingsForShop(ctx context.Context, acctID int64, platform Platform, shopID string) ([]Listing, error) {
var vs []Listing
for _, v := range getDevListings(acctID) {
@@ -292,6 +349,66 @@ func (db *Store) GetListingsForShop(ctx context.Context, acctID int64, platform
return vs, nil
}
func (db *Store) GetMockListingsForShop(ctx context.Context, acctID int64, platform Platform, shopID string) ([]Listing, error) {
in, ok := getMockShopSchemaInfo(platform)
if !ok {
return nil, consts.ErrNotFound
}
rows, err := db.db.Query(
ctx,
fmt.Sprintf(
`
SELECT
listing_id,
sku,
name,
description,
"count"
FROM
%s
WHERE
account_id = @account_id
AND shop_id = @shop_id
`,
in.listingsTable,
),
pgx.NamedArgs{
"account_id": acctID,
"shop_id": shopID,
},
)
if err != nil {
return nil, fmt.Errorf("failed to perform query: %w", err)
}
vs, err := pgx.CollectRows(rows, pgx.RowToStructByNameLax[struct {
Listing_id string
SKU string
Name string
Description string
Count int64
}])
if err != nil {
return nil, fmt.Errorf("failed to scan rows: %w", err)
}
listings := make([]Listing, len(vs))
for i, v := range vs {
listings[i] = Listing{
AccountShopListingIDs: NewAccountIDs(acctID).
ShopID(in.platform, shopID).
ListingID(v.Listing_id),
SKU: v.SKU,
Name: v.Name,
Description: v.Description,
Count: v.Count,
}
}
return listings, nil
}
// additional context
func (db *Store) GetAccountPointerByUserID(ctx context.Context, userID string) (*Account, error) {
+112 -21
View File
@@ -412,28 +412,19 @@ func (db *Store) ListMockListingsForShop(ctx context.Context, acctID int64, plat
ctx,
fmt.Sprintf(
`
WITH shop_exists(shop_exists) AS (
SELECT
true
FROM
%s
WHERE
account_id = @account_id
AND shop_id = @shop_id
)
SELECT
COALESCE(shop_exists, false) AS shop_exists,
listing_id,
sku,
name,
description,
"count"
true AS shop_exists,
l.listing_id,
l.sku,
l.name,
l.description,
l."count"
FROM
shop_exists
%s AS s
LEFT JOIN
%s
ON
TRUE
%s AS l
USING
(account_id, shop_id)
WHERE
(account_id IS NULL OR account_id = @account_id)
AND (shop_id IS NULL OR shop_id = @shop_id)
@@ -466,11 +457,11 @@ func (db *Store) ListMockListingsForShop(ctx context.Context, acctID int64, plat
// check if the shop exists, and confirm there were actually listings (LEFT JOIN)
if len(vs) == 0 || !vs[0].Shop_exists {
fmt.Println("TEST")
if len(vs) == 0 {
return nil, fmt.Errorf("%w: shop not found", consts.ErrNotFound)
}
if !vs[0].SKU.Valid {
// shop exists, but there are not listings
return nil, nil
}
@@ -530,6 +521,106 @@ func getMockShopTableName(platform Platform) (string, error) {
}
}
type mockShopSchemaInfo struct {
platform Platform
shopTable string
listingsTable string
syncGroupListingDraftsTable string
}
func getMockShopSchemaInfo(platform Platform) (mockShopSchemaInfo, bool) {
for _, in := range getAllMockShopSchemaInfos() {
if in.platform == platform {
return in, true
}
}
return mockShopSchemaInfo{}, false
}
func getAllMockShopSchemaInfos() []mockShopSchemaInfo {
return []mockShopSchemaInfo{
{
platform: Amazon,
shopTable: "mock.shop_amazon",
listingsTable: "mock.shop_amazon_listings",
syncGroupListingDraftsTable: "mock.shop_amazon_sync_group_listing_drafts",
},
{
platform: BigCartel,
shopTable: "mock.shop_big_cartel",
listingsTable: "mock.shop_big_cartel_listings",
syncGroupListingDraftsTable: "mock.shop_big_cartel_sync_group_listing_drafts",
},
{
platform: Ebay,
shopTable: "mock.shop_ebay",
listingsTable: "mock.shop_ebay_listings",
syncGroupListingDraftsTable: "mock.shop_ebay_sync_group_listing_drafts",
},
{
platform: Ecwid,
shopTable: "mock.shop_ecwid",
listingsTable: "mock.shop_ecwid_listings",
syncGroupListingDraftsTable: "mock.shop_ecwid_sync_group_listing_drafts",
},
{
platform: Etsy,
shopTable: "mock.shop_etsy",
listingsTable: "mock.shop_etsy_listings",
syncGroupListingDraftsTable: "mock.shop_etsy_sync_group_listing_drafts",
},
{
platform: Shopify,
shopTable: "mock.shop_shopify",
listingsTable: "mock.shop_shopify_listings",
syncGroupListingDraftsTable: "mock.shop_shopify_sync_group_listing_drafts",
},
{
platform: SquareOnline,
shopTable: "mock.shop_square_online",
listingsTable: "mock.shop_square_online_listings",
syncGroupListingDraftsTable: "mock.shop_square_online_sync_group_listing_drafts",
},
{
platform: Squarespace,
shopTable: "mock.shop_squarespace",
listingsTable: "mock.shop_squarespace_listings",
syncGroupListingDraftsTable: "mock.shop_squarespace_sync_group_listing_drafts",
},
{
platform: Tiktok,
shopTable: "mock.shop_tiktok",
listingsTable: "mock.shop_tiktok_listings",
syncGroupListingDraftsTable: "mock.shop_tiktok_sync_group_listing_drafts",
},
{
platform: WalmartMarketplace,
shopTable: "mock.shop_walmart_marketplace",
listingsTable: "mock.shop_walmart_marketplace_listings",
syncGroupListingDraftsTable: "mock.shop_walmart_marketplace_sync_group_listing_drafts",
},
{
platform: Wix,
shopTable: "mock.shop_wix",
listingsTable: "mock.shop_wix_listings",
syncGroupListingDraftsTable: "mock.shop_wix_sync_group_listing_drafts",
},
{
platform: WooCommerce,
shopTable: "mock.shop_woo_commerce",
listingsTable: "mock.shop_woo_commerce_listings",
syncGroupListingDraftsTable: "mock.shop_woo_commerce_sync_group_listing_drafts",
},
{
platform: Zoho,
shopTable: "mock.shop_zoho",
listingsTable: "mock.shop_zoho_listings",
syncGroupListingDraftsTable: "mock.shop_zoho_sync_group_listing_drafts",
},
}
}
func getMockShopAndListingsTableNames(platform Platform) (shop string, listing string, err error) {
shop, err = getMockShopTableName(platform)
if err != nil {
@@ -44,10 +44,18 @@ func (v_ctx *StoreWithContext) GetShops(acctID int64) ([]AccountShop, error) {
return v_ctx.Store.GetShops(v_ctx.ctx, acctID)
}
func (v_ctx *StoreWithContext) GetMockShops(acctID int64) ([]AccountShop, error) {
return v_ctx.Store.GetMockShops(v_ctx.ctx, acctID)
}
func (v_ctx *StoreWithContext) GetListingsForShop(acctID int64, platform Platform, shopID string) ([]Listing, error) {
return v_ctx.Store.GetListingsForShop(v_ctx.ctx, acctID, platform, shopID)
}
func (v_ctx *StoreWithContext) GetMockListingsForShop(acctID int64, platform Platform, shopID string) ([]Listing, error) {
return v_ctx.Store.GetMockListingsForShop(v_ctx.ctx, acctID, platform, shopID)
}
func (v_ctx *StoreWithContext) GetAccountPointerByUserID(userID string) (*Account, error) {
return v_ctx.Store.GetAccountPointerByUserID(v_ctx.ctx, userID)
}
@@ -96,26 +104,50 @@ func (v_ctx *StoreWithContext) CreateSyncGroupListingDraft(acctID int64) (int, e
return v_ctx.Store.CreateSyncGroupListingDraft(v_ctx.ctx, acctID)
}
func (v_ctx *StoreWithContext) CreateMockSyncGroupListingDraft(acctID int64) (int, error) {
return v_ctx.Store.CreateMockSyncGroupListingDraft(v_ctx.ctx, acctID)
}
func (v_ctx *StoreWithContext) GetSyncGroupListingDraft(acctID int64, orderIndex int) (SyncGroupListingDraft, error) {
return v_ctx.Store.GetSyncGroupListingDraft(v_ctx.ctx, acctID, orderIndex)
}
func (v_ctx *StoreWithContext) GetMockSyncGroupListingDraft(acctID int64, orderIndex int) (SyncGroupListingDraft, error) {
return v_ctx.Store.GetMockSyncGroupListingDraft(v_ctx.ctx, acctID, orderIndex)
}
func (v_ctx *StoreWithContext) SetShopInSyncGroupListingDraft(acctID int64, orderIndex int, platform Platform, shopID string) error {
return v_ctx.Store.SetShopInSyncGroupListingDraft(v_ctx.ctx, acctID, orderIndex, platform, shopID)
}
func (v_ctx *StoreWithContext) SetShopInMockSyncGroupListingDraft(acctID int64, orderIndex int, platform Platform, shopID string) error {
return v_ctx.Store.SetShopInMockSyncGroupListingDraft(v_ctx.ctx, acctID, orderIndex, platform, shopID)
}
func (v_ctx *StoreWithContext) SetListingInSyncGroupListingDraft(acctID int64, orderIndex int, listingID string) error {
return v_ctx.Store.SetListingInSyncGroupListingDraft(v_ctx.ctx, acctID, orderIndex, listingID)
}
func (v_ctx *StoreWithContext) SetListingInMockSyncGroupListingDraft(acctID int64, orderIndex int, listingID string) error {
return v_ctx.Store.SetListingInMockSyncGroupListingDraft(v_ctx.ctx, acctID, orderIndex, listingID)
}
func (v_ctx *StoreWithContext) DeleteSyncGroupListingDraft(acctID int64, orderIndex int) (int, error) {
return v_ctx.Store.DeleteSyncGroupListingDraft(v_ctx.ctx, acctID, orderIndex)
}
func (v_ctx *StoreWithContext) DeleteMockSyncGroupListingDraft(acctID int64, orderIndex int) error {
return v_ctx.Store.DeleteMockSyncGroupListingDraft(v_ctx.ctx, acctID, orderIndex)
}
func (v_ctx *StoreWithContext) GetSyncGroupListingDrafts(acctID int64) ([]SyncGroupListingDraft, error) {
return v_ctx.Store.GetSyncGroupListingDrafts(v_ctx.ctx, acctID)
}
func (v_ctx *StoreWithContext) GetMockSyncGroupListingDrafts(acctID int64) ([]SyncGroupListingDraft, error) {
return v_ctx.Store.GetMockSyncGroupListingDrafts(v_ctx.ctx, acctID)
}
func (v_ctx *StoreWithContext) SaveNewSyncGroup(acctID int64) (SyncGroup, error) {
return v_ctx.Store.SaveNewSyncGroup(v_ctx.ctx, acctID)
}
+381 -5
View File
@@ -8,6 +8,7 @@ import (
"slices"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype"
)
type (
@@ -28,6 +29,7 @@ type (
SyncGroupID int64
}
// TODO: the id ACTUALLY is the account_id and order_index
SyncGroupListingDraft struct {
AccountShopIDs
ListingID string
@@ -75,6 +77,44 @@ func (db *Store) CreateSyncGroupListingDraft(ctx context.Context, acctID int64)
return orderIndex, nil
}
func (db *Store) CreateMockSyncGroupListingDraft(ctx context.Context, acctID int64) (orderIndex int, err error) {
rows, err := db.db.Query(
ctx,
`
WITH max_order_index(max_index) AS (
SELECT
MAX(order_index) AS max_index
FROM
mock.sync_group_listing_draft_order_indexes
)
INSERT INTO
mock.sync_group_listing_draft_order_indexes (
account_id,
order_index
)
SELECT
@account_id,
COALESCE(max_index, -1) + 1
FROM
max_order_index
RETURNING
order_index
`,
pgx.NamedArgs{
"account_id": acctID,
},
)
if err != nil {
return 0, fmt.Errorf("failed to perform query: %w", err)
}
if orderIndex, err = pgx.CollectExactlyOneRow(rows, pgx.RowTo[int]); err != nil {
return 0, fmt.Errorf("failed to scan rows: %w", err)
}
return orderIndex, nil
}
func (db *Store) GetSyncGroupListingDraft(ctx context.Context, acctID int64, orderIndex int) (SyncGroupListingDraft, error) {
rows, err := db.db.Query(
ctx,
@@ -124,8 +164,96 @@ func (db *Store) GetSyncGroupListingDraft(ctx context.Context, acctID int64, ord
}, nil
}
func (db *Store) GetMockSyncGroupListingDraft(ctx context.Context, acctID int64, orderIndex int) (SyncGroupListingDraft, error) {
tx, err := db.db.BeginTx(ctx, pgx.TxOptions{
AccessMode: pgx.ReadOnly,
})
if err != nil {
return SyncGroupListingDraft{}, fmt.Errorf("failed to begin transaction: %w", err)
}
defer tx.Rollback(ctx)
rows, err := tx.Query(
ctx,
`
SELECT
true
FROM
mock.sync_group_listing_draft_order_indexes
WHERE
account_id = @account_id
AND order_index = @order_index
`,
pgx.NamedArgs{
"account_id": acctID,
"order_index": orderIndex,
},
)
if err != nil {
return SyncGroupListingDraft{}, fmt.Errorf("failed to scan rows: %w", err)
}
if _, err := pgx.CollectExactlyOneRow(rows, pgx.RowTo[bool]); err != nil {
return SyncGroupListingDraft{}, fmt.Errorf("failed to scan rows: %w", err)
}
for _, info := range getAllMockShopSchemaInfos() {
rows, err := tx.Query(
ctx,
fmt.Sprintf(
`
SELECT
shop_id,
listing_id
FROM
%s
WHERE
account_id = @account_id
AND order_index = @order_index
`,
info.syncGroupListingDraftsTable,
),
pgx.NamedArgs{
"account_id": acctID,
"order_index": orderIndex,
},
)
if err != nil {
return SyncGroupListingDraft{}, fmt.Errorf("failed to perform query: %w", err)
}
v, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByNameLax[struct {
Shop_id pgtype.Text
Listing_id pgtype.Text
}])
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
continue
}
return SyncGroupListingDraft{}, fmt.Errorf("faild to scan row: %w", err)
}
return SyncGroupListingDraft{
AccountShopIDs: NewAccountIDs(acctID).
ShopID(info.platform, v.Shop_id.String),
ListingID: v.Listing_id.String,
OrderIndex: orderIndex,
}, nil
}
if err := tx.Commit(ctx); err != nil {
return SyncGroupListingDraft{}, fmt.Errorf("failed to commit transaction: %w", err)
}
return SyncGroupListingDraft{
AccountShopIDs: NewAccountIDs(acctID).
ShopID("", ""),
OrderIndex: orderIndex,
}, nil
}
func (db *Store) SetShopInSyncGroupListingDraft(ctx context.Context, acctID int64, orderIndex int, platform Platform, shopID string) error {
tags, err := db.db.Exec(
tag, err := db.db.Exec(
ctx,
`
UPDATE
@@ -148,15 +276,106 @@ func (db *Store) SetShopInSyncGroupListingDraft(ctx context.Context, acctID int6
if err != nil {
return fmt.Errorf("failed to perform query: %w", err)
}
if tags.RowsAffected() != 1 {
if tag.RowsAffected() != 1 {
return consts.ErrNotFound
}
return nil
}
func (db *Store) SetShopInMockSyncGroupListingDraft(ctx context.Context, acctID int64, orderIndex int, platform Platform, shopID string) error {
info, ok := getMockShopSchemaInfo(platform)
if !ok {
return fmt.Errorf("%w: unrecognized platform: %s", consts.ErrNotFound, platform)
}
tx, err := db.db.Begin(ctx)
if err != nil {
return fmt.Errorf("failed to start transaction: %w", err)
}
defer tx.Rollback(ctx)
_, err = tx.Exec(
ctx,
`
DELETE FROM
mock.sync_group_listing_draft_order_indexes
WHERE
account_id = @account_id
AND order_index = @order_index
RETURNING
account_id,
order_index
`,
pgx.NamedArgs{
"account_id": acctID,
"order_index": orderIndex,
},
)
if err != nil {
return fmt.Errorf("failed to perform query deleting existing index: %w", err)
}
_, err = tx.Exec(
ctx,
`
INSERT INTO
mock.sync_group_listing_draft_order_indexes (
account_id,
order_index
)
VALUES (
@account_id,
@order_index
)
`,
pgx.NamedArgs{
"account_id": acctID,
"order_index": orderIndex,
},
)
if err != nil {
// TODO: handle error where account doesn't exist?
return fmt.Errorf("failed to perform query inserting new index: %w", err)
}
_, err = tx.Exec(
ctx,
fmt.Sprintf(
`
INSERT INTO
%s (
account_id,
order_index,
shop_id
)
VALUES (
@account_id,
@order_index,
@shop_id
)
`,
info.syncGroupListingDraftsTable,
),
pgx.NamedArgs{
"account_id": acctID,
"order_index": orderIndex,
"shop_id": shopID,
},
)
if err != nil {
return fmt.Errorf("failed to perform query inserting specific shop index: %w", err)
}
if err := tx.Commit(ctx); err != nil {
return fmt.Errorf("failed to commit transaction: %w", err)
}
return nil
}
func (db *Store) SetListingInSyncGroupListingDraft(ctx context.Context, acctID int64, orderIndex int, listingID string) error {
tags, err := db.db.Exec(
tag, err := db.db.Exec(
ctx,
`
UPDATE
@@ -176,13 +395,47 @@ func (db *Store) SetListingInSyncGroupListingDraft(ctx context.Context, acctID i
if err != nil {
return fmt.Errorf("failed to perform query: %w", err)
}
if tags.RowsAffected() != 1 {
if tag.RowsAffected() != 1 {
return consts.ErrNotFound
}
return nil
}
func (db *Store) SetListingInMockSyncGroupListingDraft(ctx context.Context, acctID int64, orderIndex int, listingID string) error {
for _, info := range getAllMockShopSchemaInfos() {
tag, err := db.db.Exec(
ctx,
fmt.Sprintf(
`
UPDATE
%s
SET
listing_id = @listing_id
WHERE
account_id = @account_id
AND order_index = @order_index
`,
info.syncGroupListingDraftsTable,
),
pgx.NamedArgs{
"account_id": acctID,
"order_index": orderIndex,
"listing_id": listingID,
},
)
if err != nil {
return fmt.Errorf("failed to perform query: %w", err)
}
if tag.RowsAffected() > 0 {
return nil
}
}
return consts.ErrNotFound
}
func (db *Store) DeleteSyncGroupListingDraft(ctx context.Context, acctID int64, orderIndex int) (numOfRows int, err error) {
rows, err := db.db.Query(
ctx,
@@ -238,6 +491,31 @@ func (db *Store) DeleteSyncGroupListingDraft(ctx context.Context, acctID int64,
return r.Num_rows, nil
}
func (db *Store) DeleteMockSyncGroupListingDraft(ctx context.Context, acctID int64, orderIndex int) error {
tag, err := db.db.Exec(
ctx,
`
DELETE FROM
mock.sync_group_listing_draft_order_indexes
WHERE
account_id = @account_id
AND order_index = @order_index
`,
pgx.NamedArgs{
"account_id": acctID,
"order_index": orderIndex,
},
)
if err != nil {
return fmt.Errorf("failed to perform query: %w", err)
}
if tag.RowsAffected() != 1 {
return consts.ErrNotFound
}
return nil
}
func (db *Store) GetSyncGroupListingDrafts(ctx context.Context, acctID int64) ([]SyncGroupListingDraft, error) {
rows, err := db.db.Query(
ctx,
@@ -296,7 +574,105 @@ func (db *Store) GetSyncGroupListingDrafts(ctx context.Context, acctID int64) ([
return listings, nil
}
// TODO: test
func (db *Store) GetMockSyncGroupListingDrafts(ctx context.Context, acctID int64) ([]SyncGroupListingDraft, error) {
tx, err := db.db.BeginTx(ctx, pgx.TxOptions{
AccessMode: pgx.ReadOnly,
})
if err != nil {
return nil, fmt.Errorf("failed to begin transaction: %w", err)
}
defer tx.Rollback(ctx)
rows, err := tx.Query(
ctx,
`
SELECT
order_index
FROM
mock.sync_group_listing_draft_order_indexes
WHERE
account_id = @account_id
`,
pgx.NamedArgs{
"account_id": acctID,
},
)
if err != nil {
return nil, fmt.Errorf("failed to perform query: %w", err)
}
indexes, err := pgx.CollectRows(rows, pgx.RowTo[int])
if err != nil {
return nil, fmt.Errorf("failed to scan rows: %w", err)
}
listingsByOrderIndex := make(map[int]SyncGroupListingDraft, len(indexes))
for _, n := range indexes {
listingsByOrderIndex[n] = SyncGroupListingDraft{
AccountShopIDs: NewAccountIDs(acctID).
ShopID("", ""),
OrderIndex: n,
}
}
for _, info := range getAllMockShopSchemaInfos() {
rows, err := tx.Query(
ctx,
fmt.Sprintf(
`
SELECT
shop_id,
order_index,
listing_id
FROM
%s
WHERE
account_id = @account_id
`,
info.syncGroupListingDraftsTable,
),
pgx.NamedArgs{
"account_id": acctID,
},
)
if err != nil {
return nil, fmt.Errorf("failed to perform query: %w", err)
}
vs, err := pgx.CollectRows(rows, pgx.RowToStructByNameLax[struct {
Shop_id pgtype.Text
Order_index pgtype.Int8
Listing_id pgtype.Text
}])
if err != nil {
return nil, fmt.Errorf("failed to scan rows: %w", err)
}
for _, v := range vs {
n := int(v.Order_index.Int64)
l := listingsByOrderIndex[n]
l.Platform = info.platform
l.ShopID = v.Shop_id.String
l.ListingID = v.Listing_id.String
listingsByOrderIndex[n] = l
}
}
listings := make([]SyncGroupListingDraft, 0, len(listingsByOrderIndex))
for _, v := range listingsByOrderIndex {
listings = append(listings, v)
}
slices.SortFunc(listings, func(a, b SyncGroupListingDraft) int {
return a.OrderIndex - b.OrderIndex
})
if err := tx.Commit(ctx); err != nil {
return nil, fmt.Errorf("failed to commit transaction: %w", err)
}
return listings, nil
}
func (db *Store) SaveNewSyncGroup(ctx context.Context, acctID int64) (SyncGroup, error) {
txn, err := db.db.Begin(ctx)
if err != nil {