package meiliService import ( "fmt" "regexp" "strconv" "strings" "time" "git.ma-al.com/goc_daniel/b2b/app/config" "git.ma-al.com/goc_daniel/b2b/app/repos/productDescriptionRepo" constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data" "github.com/meilisearch/meilisearch-go" ) type MeiliService struct { productDescriptionRepo productDescriptionRepo.UIProductDescriptionRepo meiliClient meilisearch.ServiceManager } func New() *MeiliService { client := meilisearch.New( config.Get().MailiSearch.ServerURL, meilisearch.WithAPIKey(config.Get().MailiSearch.ApiKey), ) return &MeiliService{ meiliClient: client, productDescriptionRepo: productDescriptionRepo.New(), } } // ==================================== FOR TESTING ONLY ==================================== func (s *MeiliService) CreateIndex(id_lang uint) error { indexName := "meili_products_shop" + strconv.FormatInt(constdata.SHOP_ID, 10) + "_lang" + strconv.FormatInt(int64(id_lang), 10) products, err := s.productDescriptionRepo.GetMeiliProducts(id_lang) for i := 0; i < len(products); i++ { products[i].Description = cleanHTML(products[i].Description) products[i].DescriptionShort = cleanHTML(products[i].DescriptionShort) products[i].Usage = cleanHTML(products[i].Usage) } primaryKey := "ProductID" docOptions := &meilisearch.DocumentOptions{ PrimaryKey: &primaryKey, SkipCreation: false, } task, err := s.meiliClient.Index(indexName).AddDocuments(products, docOptions) if err != nil { return fmt.Errorf("meili AddDocuments error: %w", err) } finishedTask, err := s.meiliClient.WaitForTask(task.TaskUID, 500*time.Millisecond) fmt.Printf("Task status: %s\n", finishedTask.Status) fmt.Printf("Task error: %s\n", finishedTask.Error) filterableAttributes := []interface{}{ "CategoryID", "CategoryIDs", } task, err = s.meiliClient.Index(indexName).UpdateFilterableAttributes(&filterableAttributes) if err != nil { return fmt.Errorf("meili AddDocuments error: %w", err) } finishedTask, err = s.meiliClient.WaitForTask(task.TaskUID, 500*time.Millisecond) fmt.Printf("Task status: %s\n", finishedTask.Status) fmt.Printf("Task error: %s\n", finishedTask.Error) displayedAttributes := []string{ "ProductID", "Name", "EAN13", "Reference", "Variations", "CoverImage", } task, err = s.meiliClient.Index(indexName).UpdateDisplayedAttributes(&displayedAttributes) if err != nil { return fmt.Errorf("meili AddDocuments error: %w", err) } finishedTask, err = s.meiliClient.WaitForTask(task.TaskUID, 500*time.Millisecond) fmt.Printf("Task status: %s\n", finishedTask.Status) fmt.Printf("Task error: %s\n", finishedTask.Error) searchableAttributes := []string{ "Name", "DescriptionShort", "Reference", "EAN13", "CategoryName", "Description", "Usage", } task, err = s.meiliClient.Index(indexName).UpdateSearchableAttributes(&searchableAttributes) if err != nil { return fmt.Errorf("meili AddDocuments error: %w", err) } finishedTask, err = s.meiliClient.WaitForTask(task.TaskUID, 500*time.Millisecond) fmt.Printf("Task status: %s\n", finishedTask.Status) fmt.Printf("Task error: %s\n", finishedTask.Error) return err } // ==================================== FOR TESTING ONLY ==================================== func (s *MeiliService) Test(id_lang uint) (meilisearch.SearchResponse, error) { indexName := "meili_products_shop" + strconv.FormatInt(constdata.SHOP_ID, 10) + "_lang" + strconv.FormatInt(int64(id_lang), 10) searchReq := &meilisearch.SearchRequest{ Limit: 4, Facets: []string{ "CategoryID", }, } // Perform search results, err := s.meiliClient.Index(indexName).Search("mat", searchReq) if err != nil { fmt.Printf("Meilisearch error: %v\n", err) return meilisearch.SearchResponse{}, err } fmt.Printf("Search results for query 'mat' in %s: %d hits\n", indexName, len(results.Hits)) return *results, nil } // Search performs a full-text search on the specified index func (s *MeiliService) Search(id_lang uint, query string, id_category uint) (meilisearch.SearchResponse, error) { indexName := "meili_products_shop" + strconv.FormatInt(constdata.SHOP_ID, 10) + "_lang" + strconv.FormatInt(int64(id_lang), 10) filter_query := "Active = 1" if id_category != 0 { // Use CategoryIDs to include products from child categories filter_query += fmt.Sprintf(" AND CategoryIDs = %d", id_category) } searchReq := &meilisearch.SearchRequest{ Limit: 30, Facets: []string{ "CategoryID", }, Filter: filter_query, } results, err := s.meiliClient.Index(indexName).Search(query, searchReq) if err != nil { fmt.Printf("Meilisearch search error: %v\n", err) return meilisearch.SearchResponse{}, err } return *results, nil } // HealthCheck checks if Meilisearch is healthy and accessible func (s *MeiliService) HealthCheck() (*meilisearch.Health, error) { health, err := s.meiliClient.Health() if err != nil { return nil, fmt.Errorf("meilisearch health check failed: %w", err) } return health, nil } // GetIndexSettings retrieves the current settings for a specific index func (s *MeiliService) GetIndexSettings(id_lang uint) (map[string]interface{}, error) { indexName := "meili_products_shop" + strconv.FormatInt(constdata.SHOP_ID, 10) + "_lang" + strconv.FormatInt(int64(id_lang), 10) index := s.meiliClient.Index(indexName) result := make(map[string]interface{}) // Get searchable attributes searchable, err := index.GetSearchableAttributes() if err == nil { result["searchableAttributes"] = searchable } // Get filterable attributes filterable, err := index.GetFilterableAttributes() if err == nil { result["filterableAttributes"] = filterable } // Get displayed attributes displayed, err := index.GetDisplayedAttributes() if err == nil { result["displayedAttributes"] = displayed } // Get ranking rules ranking, err := index.GetRankingRules() if err == nil { result["rankingRules"] = ranking } // Get distinct attribute distinct, err := index.GetDistinctAttribute() if err == nil && distinct != nil { result["distinctAttribute"] = *distinct } // Get typo tolerance typo, err := index.GetTypoTolerance() if err == nil { result["typoTolerance"] = typo } return result, nil } // remove all tags from HTML text func cleanHTML(s string) string { // Simple regex to remove all HTML tags re := regexp.MustCompile(`<[^>]*>`) result := re.ReplaceAllString(s, "") // Replace multiple spaces with single space result = regexp.MustCompile(`\s+`).ReplaceAllString(result, " ") return strings.TrimSpace(result) }