Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 44 additions & 7 deletions sdk/builders/fluent/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,63 @@ package fluent

import (
"context"
"encoding/json"
"fmt"

"github.com/nudibranches-tech/bifrost-hyperfluid-sdk-dev/sdk/utils"
)

type OriginalFilePayload struct {
OriginalFilePath string `json:"original_file_path"`
SourceDataDockID string `json:"source_data_dock_id"`
SourceFileName string `json:"source_filename"`
}

type DocumentRecord struct {
Name string `json:"name"`
Content string `json:"content"`
Summary string `json:"summary"`
HfContext string `json:"hf_context"`
OriginalFile string `json:"original_file"`
Categories string `json:"categories"`
RlsLabels string `json:"rls_labels"`
Name string `json:"name"`
Content string `json:"content"`
Summary string `json:"summary"`
HfContext string `json:"hf_context"`
OriginalFile OriginalFilePayload `json:"original_file"`
Categories string `json:"categories"`
RlsLabels string `json:"rls_labels"`
}

type DocumentResult struct {
Record DocumentRecord `json:"record"`
Score float64 `json:"score"`
}

func (dr *DocumentRecord) UnmarshalJSON(data []byte) error {
type alias DocumentRecord
aux := &struct {
OriginalFile json.RawMessage `json:"original_file"`
*alias
}{
alias: (*alias)(dr),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
if len(aux.OriginalFile) == 0 {
return nil
}
if aux.OriginalFile[0] == '"' {
var inner string
if err := json.Unmarshal(aux.OriginalFile, &inner); err != nil {
return fmt.Errorf("unquote failed: %w", err)
}
if err := json.Unmarshal([]byte(inner), &dr.OriginalFile); err != nil {
return fmt.Errorf("inner decode failed: %w", err)
}
} else {
if err := json.Unmarshal(aux.OriginalFile, &dr.OriginalFile); err != nil {
return fmt.Errorf("direct decode failed: %w", err)
}
}
return nil
}

type SearchResults struct {
Results []DocumentResult `json:"results"`
Total int `json:"total"`
Expand Down
108 changes: 66 additions & 42 deletions usage_examples/fluent_api_examples.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"context"
"fmt"
"log"
"os"
"time"

Expand All @@ -13,46 +14,74 @@ import (
// This file demonstrates the new fluent API for the Bifrost SDK.
// The fluent API provides a more intuitive and user-friendly way to interact with the SDK.

/*
func runSearchExample() {
fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
fmt.Println("🎯 Search Example: Full-Text Search")
fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")

config := getConfig()
client := sdk.NewClient(config)

projectID := getEnv("BIFROST_DATADOCK_ID", "")
catalog := getEnv("BIFROST_TEST_CATALOG", "iceberg")
schema := getEnv("BIFROST_TEST_SCHEMA", "public")
table := getEnv("BIFROST_TEST_TABLE", "text_files")

if projectID == "" {
fmt.Println("⚠️ Skipping: BIFROST_DATADOCK_ID not set")
fmt.Println()
return
}
func runSearchExample() {
fmt.Println("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
fmt.Println("🎯 Search Example: Full‑Text Search")
fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")

fmt.Println("📝 Full-text search query:")
fmt.Printf(" DataDock: %s\n", projectID)
fmt.Printf(" Searching in: %s.%s.%s\n", catalog, schema, table)
fmt.Println()
// ---- 1️⃣ Build config & client (must be non‑nil) ----
cfg := getConfig()
if cfg.BaseURL == "" {
log.Fatal("❌ Base URL not set – cannot create SDK client")
}
client := sdk.NewClient(cfg)
if client == nil {
log.Fatal("❌ sdk.NewClient returned nil – check configuration")
}

// ---- 2️⃣ Pull required identifiers from env ----
projectID := getEnv("BIFROST_DATADOCK_ID", "")
catalog := getEnv("BIFROST_TEST_CATALOG", "iceberg")
schema := getEnv("BIFROST_TEST_SCHEMA", "public")
table := getEnv("BIFROST_TEST_TABLE", "text_files")

// Search for content
resp, _ := client.Search().
Query("rapport ventes").
DataDock(projectID). // ✅ Use the actual UUID variable
Catalog(catalog). // ✅ Use actual catalog
Schema(schema). // ✅ Use actual schema
Table(table). // ✅ Use actual table
Columns("content", "summary"). // Adjust columns based on your table
Limit(10).
Execute(context.Background())

fmt.Println(resp.Results)
if projectID == "" {
fmt.Println("⚠️ Skipping: BIFROST_DATADOCK_ID not set")
fmt.Println()
return
}
*/

// ---- 3️⃣ Show what we are about to do ----
fmt.Println("📝 Full‑text search query:")
fmt.Printf(" DataDock: %s\n", projectID)
fmt.Printf(" Searching in: %s.%s.%s\n\n", catalog, schema, table)

// ---- 4️⃣ Build the fluent request ----
builder := client.Search().
Query("rapport ventes").
DataDock(projectID).
Catalog(catalog).
Schema(schema).
Table(table).
Columns("content", "summary", "original_file"). // <-- include original_file
Limit(10)

// ---- 5️⃣ Execute and **handle the error** ----
results, err := builder.Execute(context.Background())
if err != nil {
// The builder already validates required fields, so any error here
// is a network/API problem or a JSON‑unmarshal issue.
log.Fatalf("❌ Search execution failed: %v", err)
}

// ---- 6️⃣ Print a concise summary ----
fmt.Printf("✅ Got %d result(s) (took %d ms)\n", results.Total, results.TimeTakenMs)

// ---- 7️⃣ Walk the results and display the S3 URL ----
for i, r := range results.Results {
fmt.Printf("\n#%d – Score: %.3f\n", i+1, r.Score)
fmt.Printf(" Name : %s\n", r.Record.Name)
fmt.Printf(" Summary: %s\n", r.Record.Summary)

s3URL := r.Record.OriginalFile.OriginalFilePath
if s3URL != "" {
fmt.Printf(" S3 URL: %s\n", s3URL)
} else {
fmt.Println(" S3 URL: <none>")
}
}
fmt.Println()
}

/*
func runFluentAPISimpleExample() {
Expand Down Expand Up @@ -91,7 +120,6 @@ func runFluentAPISimpleExample() {
}
*/

/*
func runFluentAPIWithSelectExample() {
fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
fmt.Println("🎯 Fluent API Example 2: Query with SELECT")
Expand Down Expand Up @@ -133,7 +161,6 @@ func runFluentAPIWithSelectExample() {
handleResponse(resp, err)
fmt.Println()
}
*/

/*
func runFluentAPIComplexExample() {
Expand Down Expand Up @@ -178,7 +205,7 @@ func runFluentAPIComplexExample() {
}
*/
// Helper functions
/*

func handleResponse(resp *utils.Response, err error) {
if err != nil {
fmt.Printf("❌ Error: %s\n", err.Error())
Expand All @@ -205,7 +232,6 @@ func handleResponse(resp *utils.Response, err error) {
fmt.Printf("📦 Data: %v\n", dataMap)
}
}
*/

func runS3Example() {
fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
Expand Down Expand Up @@ -304,7 +330,6 @@ func getEnv(key, fallback string) string {
return fallback
}

/*
func splitColumns(cols string) []string {
if cols == "" {
return []string{}
Expand All @@ -327,4 +352,3 @@ func splitColumns(cols string) []string {
}
return result
}
*/
2 changes: 2 additions & 0 deletions usage_examples/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ func main() {
fmt.Println()

runS3Example()
runFluentAPIWithSelectExample()
runSearchExample()

fmt.Println()
fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
Expand Down