Stores: shopstore

Manage products, orders, and commerce entities with github.com/dracory/shopstore.

github.com/dracory/shopstore

shopstore is Dracory's e-commerce data layer. It centralizes products, categories, discounts, media, and orders using an interface-driven store so you can build shop features without rewriting persistence logic.


Highlights

  • Comprehensive domain – typed entities for Product, Category, Discount, Media, Order, and OrderLineItem with fluent getters/setters and predicates.
  • Schema via migrations – schema creation handled by migration files, not automigration.
  • Dirty tracking – entities track changed fields, ensuring updates only persist modified columns.
  • Soft deletion & metadata – consistent helpers for Metas, Meta, UpsertMetas, plus soft-delete timestamps.
  • Query builders – fluent query objects to filter, search, sort, paginate, and count across all entity types.
  • Observability – enable SQL logging via st.EnableDebug(debug); configure default timeouts and instrumentation.

Creating a Store

func NewShopStore(db *sql.DB, debug bool) (shopstore.StoreInterface, error) {
    st, err := shopstore.NewStore(shopstore.NewStoreOptions{
        DB:                     db,
        CategoryTableName:      "snv_shop_category",
        DiscountTableName:      "snv_shop_discount",
        MediaTableName:         "snv_shop_media",
        OrderTableName:         "snv_shop_order",
        OrderLineItemTableName: "snv_shop_order_line_item",
        ProductTableName:       "snv_shop_product",
    })
    if err != nil {
        return nil, err
    }
    st.EnableDebug(debug)
    return st, nil
}
  • Table names are configurable to fit existing schemas.
  • Debug is controlled via st.EnableDebug(debug) after store creation.
  • Schema creation is handled by migration files in database/migrations/ (invoked via migrations.MigrateAll(app)), not by automigration.

Working with Products

ctx := context.Background()

product := shopstore.NewProduct().
    SetTitle("Cascade Tee").
    SetDescription("Premium cotton shirt").
    SetPriceFloat(19.99).
    SetQuantityInt(25).
    SetStatus(shopstore.PRODUCT_STATUS_ACTIVE)

if err := store.ProductCreate(ctx, product); err != nil {
    log.Fatal(err)
}

products, err := store.ProductList(ctx, shopstore.NewProductQuery().
    SetStatus(shopstore.PRODUCT_STATUS_ACTIVE).
    SetLimit(20).
    SetOrderBy("created_at").
    SetSortDirection("desc"))
  • Products support inventory helpers (QuantityInt, PriceFloat, IsInStock).
  • Use ProductUpdate to persist changes; only dirty fields are included.

Orders & Line Items

order := shopstore.NewOrder().
    SetCustomerID(customerID).
    SetStatus(shopstore.ORDER_STATUS_PENDING)

if err := store.OrderCreate(ctx, order); err != nil {
    log.Fatal(err)
}

line := shopstore.NewOrderLineItem().
    SetOrderID(order.ID()).
    SetProductID(product.ID()).
    SetQuantityFloat(2).
    SetUnitPriceFloat(product.PriceFloat())

if err := store.OrderLineItemCreate(ctx, line); err != nil {
    log.Fatal(err)
}
  • Orders expose helpers for totals, taxes, and metadata.
  • Discounts and media attach through dedicated entities with consistent metadata APIs.

Query Builders

  • CategoryQuery, ProductQuery, OrderQuery, MediaQuery, etc. provide chainable filters (IDs, status, price ranges, created windows), pagination, and count toggles.
  • Combine with soft-delete options to include archived records when needed.

  • Design Principles – understand Dracory’s store architecture.
  • Entities & Interfaces – see how domain objects embed the dataobject pattern.
  • Testing – browse shopstore’s test suite for integration workflows.
  • Create Your Own Store – extend the pattern for custom commerce needs.