package queries import ( "context" "database/sql" "fmt" "strings" ) type Last10AvgPurchasePriceRow struct { ItemCode string CurrencyCode string SampleCount int AvgDocPrice float64 MinInvoiceDate sql.NullString MaxInvoiceDate sql.NullString } // LookupLast10AvgPurchasePriceByItemCodes reads from dbo.cache_last10_avg_purchase_price (Nebim/V3 MSSQL). // It is designed to be used in hot paths (save) where live invoice scans are too slow. func LookupLast10AvgPurchasePriceByItemCodes(ctx context.Context, mssqlDB *sql.DB, itemCodes []string) ([]Last10AvgPurchasePriceRow, error) { if mssqlDB == nil { return nil, fmt.Errorf("mssql db is nil") } codes := make([]string, 0, len(itemCodes)) seen := map[string]struct{}{} for _, c := range itemCodes { c = strings.TrimSpace(c) if c == "" { continue } if _, ok := seen[c]; ok { continue } seen[c] = struct{}{} codes = append(codes, c) } if len(codes) == 0 { return []Last10AvgPurchasePriceRow{}, nil } valParts := make([]string, 0, len(codes)) args := make([]any, 0, len(codes)) for i, code := range codes { valParts = append(valParts, fmt.Sprintf("(@p%d)", i+1)) args = append(args, code) } sqlText := fmt.Sprintf(` WITH C AS ( SELECT LTRIM(RTRIM(V.code)) AS ItemCode FROM (VALUES %s) AS V(code) ) SELECT T.ItemCode, T.Doc_CurrencyCode, T.sample_count, T.avg_doc_price, CONVERT(varchar(10), T.min_invoice_date, 23) AS min_invoice_date, CONVERT(varchar(10), T.max_invoice_date, 23) AS max_invoice_date FROM dbo.cache_last10_avg_purchase_price T WITH (NOLOCK) INNER JOIN C ON C.ItemCode = T.ItemCode `, strings.Join(valParts, ",")) rows, err := mssqlDB.QueryContext(ctx, sqlText, args...) if err != nil { return nil, err } defer rows.Close() out := make([]Last10AvgPurchasePriceRow, 0, len(codes)) for rows.Next() { var r Last10AvgPurchasePriceRow if err := rows.Scan(&r.ItemCode, &r.CurrencyCode, &r.SampleCount, &r.AvgDocPrice, &r.MinInvoiceDate, &r.MaxInvoiceDate); err != nil { return nil, err } r.ItemCode = strings.TrimSpace(r.ItemCode) r.CurrencyCode = strings.TrimSpace(strings.ToUpper(r.CurrencyCode)) out = append(out, r) } if err := rows.Err(); err != nil { return nil, err } return out, nil }