package productsRepo import ( "encoding/json" "fmt" "git.ma-al.com/goc_daniel/b2b/app/config" "git.ma-al.com/goc_daniel/b2b/app/db" "git.ma-al.com/goc_daniel/b2b/app/model" "git.ma-al.com/goc_daniel/b2b/app/model/dbmodel" "git.ma-al.com/goc_daniel/b2b/app/utils/query/filters" "git.ma-al.com/goc_daniel/b2b/app/utils/query/find" "git.ma-al.com/goc_marek/gormcol" "github.com/WinterYukky/gorm-extra-clause-plugin/exclause" ) type UIProductsRepo interface { GetJSON(p_id_product, p_id_shop, p_id_lang, p_id_customer, b2b_id_country, p_quantity int) (*json.RawMessage, error) Find(id_lang, userID uint, p find.Paging, filt *filters.FiltersList) (find.Found[model.ProductInList], error) } type ProductsRepo struct{} func New() UIProductsRepo { return &ProductsRepo{} } func (repo *ProductsRepo) GetJSON(p_id_product, p_id_shop, p_id_lang, p_id_customer, b2b_id_country, p_quantity int) (*json.RawMessage, error) { var productStr string // ← Scan as string first err := db.DB.Raw(`CALL get_full_product(?,?,?,?,?,?)`, p_id_product, p_id_shop, p_id_lang, p_id_customer, b2b_id_country, p_quantity). Scan(&productStr). Error if err != nil { return nil, err } if !json.Valid([]byte(productStr)) { return nil, fmt.Errorf("invalid json returned from stored procedure") } raw := json.RawMessage(productStr) return &raw, nil } func (repo *ProductsRepo) Find(id_lang, userID uint, p find.Paging, filt *filters.FiltersList) (find.Found[model.ProductInList], error) { var list []model.ProductInList var total int64 query := db.Get(). Table(gormcol.Field.Tab(dbmodel.PsProductShopCols.Active)+" AS ps"). Select(` ps.id_product AS product_id, pl.name AS name, pl.link_rewrite AS link_rewrite, CONCAT(?, '/', ims.id_image, '-small_default/', pl.link_rewrite, '.webp') AS image_link, cl.name AS category_name, p.reference AS reference, COALESCE(v.variants_number, 0) AS variants_number, sa.quantity AS quantity, COALESCE(f.is_favorite, 0) AS is_favorite `, config.Get().Image.ImagePrefix). Joins("JOIN "+dbmodel.PsProductCols.IDProduct.Tab()+" p ON p.id_product = ps.id_product"). Joins("JOIN ps_product_lang pl ON pl.id_product = ps.id_product AND pl.id_lang = ?", id_lang). Joins("JOIN ps_image_shop ims ON ims.id_product = ps.id_product AND ims.cover = 1"). Joins("JOIN ps_category_lang cl ON cl.id_category = ps.id_category_default AND cl.id_lang = ?", id_lang). Joins("JOIN ps_category_product cp ON cp.id_product = ps.id_product"). Joins("LEFT JOIN variants v ON v.id_product = ps.id_product"). Joins("LEFT JOIN favorites f ON f.id_product = ps.id_product"). Joins("LEFT JOIN ps_stock_available sa ON sa.id_product = ps.id_product AND sa.id_product_attribute = 0"). Where("ps.active = ?", 1). Group("ps.id_product"). Clauses(exclause.With{ CTEs: []exclause.CTE{ { Name: "variants", Subquery: exclause.Subquery{ DB: db.Get(). Model(&dbmodel.PsProductAttributeShop{}). Select("id_product", "COUNT(*) AS variants_number"). Group("id_product"), }, }, { Name: "favorites", Subquery: exclause.Subquery{ DB: db.Get(). Table("b2b_favorites"). Select(` product_id AS id_product, COUNT(*) > 0 AS is_favorite `). Where("user_id = ?", userID). Group("product_id"), }, }, }, }). Order("ps.id_product DESC") // Apply all filters if filt != nil { filt.ApplyAll(query) } // run counter first as query is without limit and offset err := query.Count(&total).Error if err != nil { return find.Found[model.ProductInList]{}, err } err = query. Limit(p.Limit()). Offset(p.Offset()). Find(&list).Error if err != nil { return find.Found[model.ProductInList]{}, err } return find.Found[model.ProductInList]{ Items: list, Count: uint(total), }, nil }