package queries import ( "context" "database/sql" "fmt" "strings" ) // LookupTbStokExistsByCodes checks if tbStok contains records matching the given codes. // Match rules are aligned with costing usage: // - exact sKodu (ignoring spaces) // - exact sModel // // Returns a map[code]exists. func LookupTbStokExistsByCodes(ctx context.Context, mssqlDB *sql.DB, codes []string) (map[string]bool, error) { if mssqlDB == nil { return nil, fmt.Errorf("mssql db is nil") } norm := make([]string, 0, len(codes)) seen := map[string]struct{}{} for _, c := range codes { c = strings.TrimSpace(c) if c == "" { continue } if _, ok := seen[c]; ok { continue } seen[c] = struct{}{} norm = append(norm, c) } out := map[string]bool{} for _, c := range norm { out[c] = false } if len(norm) == 0 { return out, nil } valParts := make([]string, 0, len(norm)) args := make([]any, 0, len(norm)) for i, code := range norm { valParts = append(valParts, fmt.Sprintf("(@p%d)", i+1)) args = append(args, code) } // NOTE: This endpoint is a UX validation helper and must be fast. // Keep predicates sargable: no function wrapping on tbStok columns. // // For "ignore spaces" behavior, we send both the original code and its no-space variant from input, // and match via exact equality against tbStok.sKodu. // // IMPORTANT: We intentionally do not filter by IsBlocked here because IsBlocked is nullable and // filtering requires OR logic, which can prevent index seeks and cause timeouts. This is a best-effort // existence check for UX highlighting. sqlText := fmt.Sprintf(` WITH C AS ( SELECT LTRIM(RTRIM(V.code)) AS code, REPLACE(LTRIM(RTRIM(V.code)), ' ', '') AS code_nospace FROM (VALUES %s) AS V(code) ), HIT AS ( SELECT DISTINCT C.code FROM C JOIN dbo.tbStok S WITH (NOLOCK) ON S.sKodu = C.code OR S.sKodu = C.code_nospace UNION SELECT DISTINCT C.code FROM C JOIN dbo.tbStok S WITH (NOLOCK) ON S.sModel = C.code ) SELECT C.code, CASE WHEN H.code IS NULL THEN 0 ELSE 1 END AS existsFlag FROM C LEFT JOIN HIT H ON H.code = C.code `, strings.Join(valParts, ",")) rows, err := mssqlDB.QueryContext(ctx, sqlText, args...) if err != nil { return nil, err } defer rows.Close() for rows.Next() { var code string var existsFlag int if err := rows.Scan(&code, &existsFlag); err != nil { return nil, err } code = strings.TrimSpace(code) if code == "" { continue } out[code] = existsFlag == 1 } if err := rows.Err(); err != nil { return nil, err } return out, nil }