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 viamigrations.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
ProductUpdateto 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.
Related Topics
- 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.