Go: refactor config (#17544)

Signed-off-by: Jin Hai <haijin.chn@gmail.com>
This commit is contained in:
Jin Hai
2026-07-31 17:18:45 +08:00
committed by GitHub
parent 9db2e2314a
commit 36ae39bc60
60 changed files with 2708 additions and 1040 deletions

View File

@@ -50,7 +50,7 @@ var pagerankAdjustLocks [pagerankAdjustLockCount]sync.Mutex
// baseName is the table name prefix (e.g., "ragflow_<tenant_id>")
// The full table name is built as "{baseName}_{datasetID}"
// For skill index (datasetID="skill"), tableName is just baseName and uses skill_infinity_mapping.json
func (e *infinityEngine) CreateChunkStore(ctx context.Context, baseName, datasetID string, vectorSize int, parserID string) error {
func (e *Engine) CreateChunkStore(ctx context.Context, baseName, datasetID string, vectorSize int, parserID string) error {
db, release, err := e.client.checkoutDatabase(ctx, "chunk.go")
if err != nil {
return fmt.Errorf("failed to get database: %w", err)
@@ -60,7 +60,7 @@ func (e *infinityEngine) CreateChunkStore(ctx context.Context, baseName, dataset
return e.createChunkStoreWithDB(db, baseName, datasetID, vectorSize, parserID)
}
func (e *infinityEngine) createChunkStoreWithDB(db *infinity.Database, baseName, datasetID string, vectorSize int, parserID string) error {
func (e *Engine) createChunkStoreWithDB(db *infinity.Database, baseName, datasetID string, vectorSize int, parserID string) error {
vecSize := vectorSize
// Determine table name and mapping file based on index type
@@ -268,7 +268,7 @@ func (e *infinityEngine) createChunkStoreWithDB(db *infinity.Database, baseName,
// Table name format: {baseName}_{datasetID}
// Auto-create the table if it doesn't exist
// Delete existing rows with matching IDs before insert
func (e *infinityEngine) InsertChunks(ctx context.Context, chunks []map[string]interface{}, baseName string, datasetID string) ([]string, error) {
func (e *Engine) InsertChunks(ctx context.Context, chunks []map[string]interface{}, baseName string, datasetID string) ([]string, error) {
tableName := buildChunkTableName(baseName, datasetID)
common.Info("InfinityConnection.InsertChunks called", zap.String("tableName", tableName), zap.Int("chunkCount", len(chunks)))
@@ -388,7 +388,7 @@ func (e *infinityEngine) InsertChunks(ctx context.Context, chunks []map[string]i
// UpdateChunks updates chunks in a dataset table
// Table name format: {baseName}_{datasetID}
func (e *infinityEngine) UpdateChunks(ctx context.Context, condition map[string]interface{}, newValue map[string]interface{}, baseName string, datasetID string) error {
func (e *Engine) UpdateChunks(ctx context.Context, condition map[string]interface{}, newValue map[string]interface{}, baseName string, datasetID string) error {
tableName := buildChunkTableName(baseName, datasetID)
common.Info("InfinityConnection.UpdateChunks called", zap.String("tableName", tableName), zap.Any("condition", condition))
@@ -542,7 +542,7 @@ func (e *infinityEngine) UpdateChunks(ctx context.Context, condition map[string]
}
// AdjustChunkPagerank adjusts pagerank_fea and clamps it to [minWeight, maxWeight].
func (e *infinityEngine) AdjustChunkPagerank(ctx context.Context, baseName, chunkID, datasetID string, delta, minWeight, maxWeight float64) error {
func (e *Engine) AdjustChunkPagerank(ctx context.Context, baseName, chunkID, datasetID string, delta, minWeight, maxWeight float64) error {
if baseName == "" {
return fmt.Errorf("index name cannot be empty")
}
@@ -636,7 +636,7 @@ func (e *infinityEngine) AdjustChunkPagerank(ctx context.Context, baseName, chun
// DeleteChunks deletes chunks from a dataset table
// Table name format: {baseName}_{datasetID}
// condition specifies which chunks to delete
func (e *infinityEngine) DeleteChunks(ctx context.Context, condition map[string]interface{}, baseName string, datasetID string) (int64, error) {
func (e *Engine) DeleteChunks(ctx context.Context, condition map[string]interface{}, baseName string, datasetID string) (int64, error) {
tableName := buildChunkTableName(baseName, datasetID)
db, release, err := e.client.checkoutDatabase(ctx, "chunk.go")
@@ -696,7 +696,7 @@ func (e *infinityEngine) DeleteChunks(ctx context.Context, condition map[string]
// Search searches the Infinity engine for matching chunks.
// It supports three matching types: MatchTextExpr (full-text), MatchDenseExpr (vector), and FusionExpr (combined).
// If no match expressions are provided, Search relies solely on filter (e.g., doc_id, available_int) to find results.
func (e *infinityEngine) Search(ctx context.Context, req *types.SearchRequest) (*types.SearchResult, error) {
func (e *Engine) Search(ctx context.Context, req *types.SearchRequest) (*types.SearchResult, error) {
types.LogSearchRequest("Infinity", req)
if len(req.IndexNames) == 0 {
@@ -1212,7 +1212,7 @@ func (e *infinityEngine) Search(ctx context.Context, req *types.SearchRequest) (
}
// GetChunk gets a chunk by ID
func (e *infinityEngine) GetChunk(ctx context.Context, tableName, chunkID string, datasetIDs []string) (interface{}, error) {
func (e *Engine) GetChunk(ctx context.Context, tableName, chunkID string, datasetIDs []string) (interface{}, error) {
if e.client == nil || e.client.pool == nil {
return nil, fmt.Errorf("Infinity client not initialized")
}
@@ -1478,7 +1478,7 @@ func memoryMessageStatusBool(value interface{}) bool {
}
// GetFields extracts the requested fields from Infinity search results
func (e *infinityEngine) GetFields(chunks []map[string]interface{}, fields []string) map[string]map[string]interface{} {
func (e *Engine) GetFields(chunks []map[string]interface{}, fields []string) map[string]map[string]interface{} {
result := make(map[string]map[string]interface{})
// Python: if not fields, return {}
@@ -1779,7 +1779,7 @@ func (e *infinityEngine) GetFields(chunks []map[string]interface{}, fields []str
//
// For tag_kwd field, splits values by "###" separator.
// For other fields, uses comma separation.
func (e *infinityEngine) GetAggregation(chunks []map[string]interface{}, fieldName string) []map[string]interface{} {
func (e *Engine) GetAggregation(chunks []map[string]interface{}, fieldName string) []map[string]interface{} {
if len(chunks) == 0 {
return []map[string]interface{}{}
}
@@ -1875,7 +1875,7 @@ func (e *infinityEngine) GetAggregation(chunks []map[string]interface{}, fieldNa
}
// GetChunkIDs extracts chunk IDs from Infinity search results.
func (e *infinityEngine) GetChunkIDs(chunks []map[string]interface{}) []string {
func (e *Engine) GetChunkIDs(chunks []map[string]interface{}) []string {
ids := make([]string, 0, len(chunks))
for _, chunk := range chunks {
if id, ok := chunk["id"].(string); ok {
@@ -1887,7 +1887,7 @@ func (e *infinityEngine) GetChunkIDs(chunks []map[string]interface{}) []string {
// GetHighlight generates highlighted text snippets for search results.
// Matches keywords in text and wraps them with <em> tags.
func (e *infinityEngine) GetHighlight(chunks []map[string]interface{}, keywords []string, fieldName string) map[string]string {
func (e *Engine) GetHighlight(chunks []map[string]interface{}, keywords []string, fieldName string) map[string]string {
result := make(map[string]string)
if len(chunks) == 0 || len(keywords) == 0 {
return result
@@ -1901,7 +1901,7 @@ func (e *infinityEngine) GetHighlight(chunks []map[string]interface{}, keywords
// KNNScores for Infinity - since Infinity normalizes scores during fusion,
// we just need to return a result structure that GetScores can parse.
// This matches Python's approach where Infinity doesn't use the two-pass KNN.
func (e *infinityEngine) KNNScores(ctx context.Context, chunks []map[string]interface{}, queryVector []float64, topK int) (map[string]interface{}, error) {
func (e *Engine) KNNScores(ctx context.Context, chunks []map[string]interface{}, queryVector []float64, topK int) (map[string]interface{}, error) {
if len(chunks) == 0 {
return nil, nil
}
@@ -1927,7 +1927,7 @@ func (e *infinityEngine) KNNScores(ctx context.Context, chunks []map[string]inte
// GetScores extracts similarity scores from KNN search result.
// For Infinity, it parses the result from KNNScores and extracts _score values.
func (e *infinityEngine) GetScores(knnResult map[string]interface{}) map[string]float64 {
func (e *Engine) GetScores(knnResult map[string]interface{}) map[string]float64 {
scores := make(map[string]float64)
hits, ok := knnResult["hits"].(map[string]interface{})
if !ok {
@@ -2513,11 +2513,11 @@ func transformChunkFields(chunk map[string]interface{}, embeddingCols [][2]inter
}
// DropChunkStore drops a chunk table from Infinity
func (e *infinityEngine) DropChunkStore(ctx context.Context, baseName, datasetID string) error {
func (e *Engine) DropChunkStore(ctx context.Context, baseName, datasetID string) error {
return e.dropTable(ctx, buildChunkTableName(baseName, datasetID))
}
// ChunkStoreExists checks if a chunk table exists in Infinity
func (e *infinityEngine) ChunkStoreExists(ctx context.Context, baseName, datasetID string) (bool, error) {
func (e *Engine) ChunkStoreExists(ctx context.Context, baseName, datasetID string) (bool, error) {
return e.tableExists(ctx, buildChunkTableName(baseName, datasetID))
}

View File

@@ -22,6 +22,7 @@ import (
"fmt"
"os"
"ragflow/internal/common"
"ragflow/internal/server/config"
"reflect"
"strconv"
"strings"
@@ -115,7 +116,7 @@ func ensureDeadline(ctx context.Context, timeout time.Duration) (context.Context
return context.WithTimeout(ctx, timeout)
}
func NewInfinityClient(cfg *server.InfinityConfig) (*infinityClient, error) {
func NewInfinityClient(cfg config.InfinityConfig) (*infinityClient, error) {
// Parse URI like "localhost:23817" to get IP and port
host := "127.0.0.1"
port := 23817
@@ -331,54 +332,44 @@ func (c *infinityClient) checkoutDatabase(ctx context.Context, caller string) (*
}
// Engine Infinity engine implementation using Go SDK
type infinityEngine struct {
config *server.InfinityConfig
type Engine struct {
config config.InfinityConfig
client *infinityClient
mappingFileName string
docMetaMappingFileName string
}
// NewEngine creates an Infinity engine
func NewEngine(cfg interface{}) (*infinityEngine, error) {
if cfg == nil {
return nil, fmt.Errorf("infinity config is nil, please check your configuration file for 'doc_engine.infinity' settings")
}
infConfig, ok := cfg.(*server.InfinityConfig)
if !ok {
return nil, fmt.Errorf("invalid infinity config type, expected *config.InfinityConfig")
}
if infConfig == nil {
return nil, fmt.Errorf("infinity config is nil, please check your configuration file for 'doc_engine.infinity' settings")
}
func NewEngine(infinityConfig config.InfinityConfig) (*Engine, error) {
client, err := NewInfinityClient(infConfig)
client, err := NewInfinityClient(infinityConfig)
if err != nil {
return nil, err
}
mappingFileName := infConfig.MappingFileName
mappingFileName := infinityConfig.MappingFileName
if mappingFileName == "" {
mappingFileName = "infinity_mapping.json"
}
docMetaMappingFileName := infConfig.DocMetaMappingFileName
docMetaMappingFileName := infinityConfig.DocMetaMappingFileName
if docMetaMappingFileName == "" {
docMetaMappingFileName = "doc_meta_infinity_mapping.json"
}
engine := &infinityEngine{
config: infConfig,
engine := &Engine{
config: infinityConfig,
client: client,
mappingFileName: mappingFileName,
docMetaMappingFileName: docMetaMappingFileName,
}
// Wait for Infinity to be healthy
if err := client.WaitForHealthy(context.Background(), 120*time.Second); err != nil {
if err = client.WaitForHealthy(context.Background(), 120*time.Second); err != nil {
return nil, fmt.Errorf("Infinity not healthy: %w", err)
}
// MigrateDB creates the database if it doesn't exist
if err := engine.MigrateDB(context.Background()); err != nil {
if err = engine.MigrateDB(context.Background()); err != nil {
return nil, fmt.Errorf("failed to migrate database: %w", err)
}
@@ -386,17 +377,17 @@ func NewEngine(cfg interface{}) (*infinityEngine, error) {
}
// GetType returns the engine type
func (e *infinityEngine) GetType() string {
func (e *Engine) GetType() string {
return "infinity"
}
// SupportsPageRank returns false because Infinity does not support pagerank.
func (e *infinityEngine) SupportsPageRank() bool {
func (e *Engine) SupportsPageRank() bool {
return false
}
// Ping checks if Infinity is accessible
func (e *infinityEngine) Ping(ctx context.Context) error {
func (e *Engine) Ping(ctx context.Context) error {
if e.client == nil || e.client.pool == nil {
return fmt.Errorf("Infinity client not initialized")
}
@@ -412,7 +403,7 @@ func (e *infinityEngine) Ping(ctx context.Context) error {
}
// Close closes the Infinity connection
func (e *infinityEngine) Close() error {
func (e *Engine) Close() error {
if e.client != nil && e.client.pool != nil {
return e.client.pool.Close()
}
@@ -420,7 +411,7 @@ func (e *infinityEngine) Close() error {
}
// MigrateDB creates the database if it doesn't exist
func (e *infinityEngine) MigrateDB(ctx context.Context) error {
func (e *Engine) MigrateDB(ctx context.Context) error {
conn, release, err := e.client.checkoutConn(ctx, "MigrateDB")
if err != nil {
return fmt.Errorf("failed to get connection: %w", err)

View File

@@ -30,7 +30,7 @@ import (
)
// dropTable drops a table from Infinity
func (e *infinityEngine) dropTable(ctx context.Context, tableName string) error {
func (e *Engine) dropTable(ctx context.Context, tableName string) error {
if tableName == "" {
return fmt.Errorf("table name cannot be empty")
}
@@ -60,7 +60,7 @@ func (e *infinityEngine) dropTable(ctx context.Context, tableName string) error
}
// tableExists checks if a table exists in Infinity
func (e *infinityEngine) tableExists(ctx context.Context, tableName string) (bool, error) {
func (e *Engine) tableExists(ctx context.Context, tableName string) (bool, error) {
if tableName == "" {
return false, fmt.Errorf("table name cannot be empty")
}
@@ -74,7 +74,7 @@ func (e *infinityEngine) tableExists(ctx context.Context, tableName string) (boo
return e.tableExistsWithDB(db, tableName)
}
func (e *infinityEngine) tableExistsWithDB(db *infinity.Database, tableName string) (bool, error) {
func (e *Engine) tableExistsWithDB(db *infinity.Database, tableName string) (bool, error) {
if db == nil {
return false, fmt.Errorf("database is nil")
}
@@ -291,7 +291,7 @@ func buildFilterFromCondition(condition map[string]interface{}, tableColumns map
}
// columnExists checks if a column exists in the table
func (e *infinityEngine) columnExists(table *infinity.Table, columnName string) (bool, error) {
func (e *Engine) columnExists(table *infinity.Table, columnName string) (bool, error) {
colsResp, err := table.ShowColumns()
if err != nil {
return false, err

View File

@@ -28,7 +28,7 @@ import (
// IndexDocument indexes a single document
// For skill index (tableName starts with "skill_"), uses InsertSkill
// For regular document index, returns not implemented error
func (e *infinityEngine) IndexDocument(ctx context.Context, tableName, docID string, doc interface{}) error {
func (e *Engine) IndexDocument(ctx context.Context, tableName, docID string, doc interface{}) error {
// Check if this is a skill index
if strings.HasPrefix(tableName, "skill_") {
return e.InsertSkill(ctx, tableName, docID, doc)
@@ -38,7 +38,7 @@ func (e *infinityEngine) IndexDocument(ctx context.Context, tableName, docID str
// InsertSkill inserts a skill document into skill index
// Auto-creates the table if it doesn't exist
func (e *infinityEngine) InsertSkill(ctx context.Context, tableName, docID string, doc interface{}) error {
func (e *Engine) InsertSkill(ctx context.Context, tableName, docID string, doc interface{}) error {
db, release, err := e.client.checkoutDatabase(ctx, "document.go")
if err != nil {
return fmt.Errorf("failed to get database: %w", err)
@@ -94,7 +94,7 @@ func (e *infinityEngine) InsertSkill(ctx context.Context, tableName, docID strin
// BulkIndex indexes documents in bulk
// For skill index (tableName starts with "skill_"), uses BulkInsertSkill
// For regular document index, returns not implemented error
func (e *infinityEngine) BulkIndex(ctx context.Context, tableName string, docs []interface{}) (interface{}, error) {
func (e *Engine) BulkIndex(ctx context.Context, tableName string, docs []interface{}) (interface{}, error) {
// Check if this is a skill index
if strings.HasPrefix(tableName, "skill_") {
inserted, err := e.BulkInsertSkill(ctx, tableName, docs)
@@ -107,7 +107,7 @@ func (e *infinityEngine) BulkIndex(ctx context.Context, tableName string, docs [
// For each document, deletes existing rows with the same skill_id before inserting,
// matching the behavior of InsertSkill. Creates shallow copies of input maps to
// avoid mutating caller data.
func (e *infinityEngine) BulkInsertSkill(ctx context.Context, tableName string, docs []interface{}) (int, error) {
func (e *Engine) BulkInsertSkill(ctx context.Context, tableName string, docs []interface{}) (int, error) {
db, release, err := e.client.checkoutDatabase(ctx, "document.go")
if err != nil {
return 0, fmt.Errorf("failed to get database: %w", err)
@@ -194,12 +194,12 @@ type BulkResponse struct {
}
// GetDocument gets a document
func (e *infinityEngine) GetDocument(ctx context.Context, tableName, docID string) (interface{}, error) {
func (e *Engine) GetDocument(ctx context.Context, tableName, docID string) (interface{}, error) {
return nil, fmt.Errorf("infinity get document not implemented: waiting for official Go SDK")
}
// DeleteDocument deletes a document by ID
func (e *infinityEngine) DeleteDocument(ctx context.Context, tableName, docID string) error {
func (e *Engine) DeleteDocument(ctx context.Context, tableName, docID string) error {
if tableName == "" {
return fmt.Errorf("table name cannot be empty")
}

View File

@@ -36,7 +36,7 @@ import (
// CreateMetadataStore creates a metadata table in Infinity
// tenantID is the tenant identifier used to build the table name
func (e *infinityEngine) CreateMetadataStore(ctx context.Context, tenantID string) error {
func (e *Engine) CreateMetadataStore(ctx context.Context, tenantID string) error {
db, release, err := e.client.checkoutDatabase(ctx, "metadata.go")
if err != nil {
return fmt.Errorf("failed to get database: %w", err)
@@ -46,7 +46,7 @@ func (e *infinityEngine) CreateMetadataStore(ctx context.Context, tenantID strin
return e.createMetadataStoreWithDB(db, tenantID)
}
func (e *infinityEngine) createMetadataStoreWithDB(db *infinity.Database, tenantID string) error {
func (e *Engine) createMetadataStoreWithDB(db *infinity.Database, tenantID string) error {
tableName := buildMetadataTableName(tenantID)
// Check if table already exists
@@ -138,7 +138,7 @@ func (e *infinityEngine) createMetadataStoreWithDB(db *infinity.Database, tenant
// The metadata table must already exist; the service layer is responsible
// for creating it before writing.
// Replace existing metadata with same id and kb_id
func (e *infinityEngine) InsertMetadata(ctx context.Context, metadata []map[string]interface{}, tenantID string) ([]string, error) {
func (e *Engine) InsertMetadata(ctx context.Context, metadata []map[string]interface{}, tenantID string) ([]string, error) {
tableName := buildMetadataTableName(tenantID)
common.Info("InfinityConnection.InsertMetadata called", zap.String("tableName", tableName), zap.Int("metaCount", len(metadata)))
@@ -222,7 +222,7 @@ func (e *infinityEngine) InsertMetadata(ctx context.Context, metadata []map[stri
// produced by the LLM extraction pipeline. See the CLI parser in
// internal/cli/user_parser.go (parseDevSetMeta) for the user-facing
// surface that drives this engine method.
func (e *infinityEngine) UpdateMetadata(ctx context.Context, docID string, datasetID string, metaFields map[string]interface{}, tenantID string) error {
func (e *Engine) UpdateMetadata(ctx context.Context, docID string, datasetID string, metaFields map[string]interface{}, tenantID string) error {
tableName := buildMetadataTableName(tenantID)
common.Info("InfinityConnection.UpdateMetadata called", zap.String("tableName", tableName), zap.String("docID", docID), zap.String("datasetID", datasetID))
@@ -329,7 +329,7 @@ func (e *infinityEngine) UpdateMetadata(ctx context.Context, docID string, datas
// DeleteMetadata deletes metadata from tenant's metadata table by condition
// Returns the number of deleted documents.
func (e *infinityEngine) DeleteMetadata(ctx context.Context, condition map[string]interface{}, tenantID string) (int64, error) {
func (e *Engine) DeleteMetadata(ctx context.Context, condition map[string]interface{}, tenantID string) (int64, error) {
tableName := buildMetadataTableName(tenantID)
db, release, err := e.client.checkoutDatabase(ctx, "metadata.go")
@@ -347,7 +347,7 @@ func (e *infinityEngine) DeleteMetadata(ctx context.Context, condition map[strin
return e.deleteMetadataWithTable(table, condition)
}
func (e *infinityEngine) deleteMetadataWithTable(table *infinity.Table, condition map[string]interface{}) (int64, error) {
func (e *Engine) deleteMetadataWithTable(table *infinity.Table, condition map[string]interface{}) (int64, error) {
if table == nil {
return 0, fmt.Errorf("metadata table is nil")
}
@@ -396,7 +396,7 @@ func (e *infinityEngine) deleteMetadataWithTable(table *infinity.Table, conditio
// DeleteMetadataKeys deletes specific metadata keys from a document's meta_fields.
// If deleting those keys leaves no metadata entries, the metadata row is removed.
func (e *infinityEngine) DeleteMetadataKeys(ctx context.Context, docID string, datasetID string, keys []string, tenantID string) error {
func (e *Engine) DeleteMetadataKeys(ctx context.Context, docID string, datasetID string, keys []string, tenantID string) error {
tableName := buildMetadataTableName(tenantID)
common.Info("InfinityConnection.DeleteMetadataKeys called", zap.String("tableName", tableName), zap.String("docID", docID), zap.Any("keys", keys))
@@ -539,20 +539,20 @@ func (e *infinityEngine) DeleteMetadataKeys(ctx context.Context, docID string, d
}
// DropMetadataStore drops a metadata table from Infinity
func (e *infinityEngine) DropMetadataStore(ctx context.Context, tenantID string) error {
func (e *Engine) DropMetadataStore(ctx context.Context, tenantID string) error {
tableName := buildMetadataTableName(tenantID)
return e.dropTable(ctx, tableName)
}
// MetadataStoreExists checks if a metadata table exists in Infinity
func (e *infinityEngine) MetadataStoreExists(ctx context.Context, tenantID string) (bool, error) {
func (e *Engine) MetadataStoreExists(ctx context.Context, tenantID string) (bool, error) {
tableName := buildMetadataTableName(tenantID)
return e.tableExists(ctx, tableName)
}
// SearchMetadata executes search specifically for metadata tables
// This is separate from Search() which handles only chunk tables
func (e *infinityEngine) SearchMetadata(ctx context.Context, req *types.SearchMetadataRequest) (*types.SearchMetadataResult, error) {
func (e *Engine) SearchMetadata(ctx context.Context, req *types.SearchMetadataRequest) (*types.SearchMetadataResult, error) {
tenantID := req.TenantID
common.Debug("SearchMetadata in Infinity started", zap.String("tenantID", tenantID))
@@ -788,7 +788,7 @@ const metaPushdownMaxSize = 10000
// nil -> push-down was not viable / errored / result overflowed the
// push-down cap (caller should fall back to in-memory)
// []string{} -> push-down succeeded but found 0 matching docs (empty result is definitive)
func (e *infinityEngine) FilterDocIdsByMetaPushdown(ctx context.Context, sqlDB *gorm.DB, kbIDs []string, conditions []map[string]interface{}, logic string) []string {
func (e *Engine) FilterDocIdsByMetaPushdown(ctx context.Context, sqlDB *gorm.DB, kbIDs []string, conditions []map[string]interface{}, logic string) []string {
if len(conditions) == 0 || len(kbIDs) == 0 {
return nil
}

View File

@@ -286,7 +286,7 @@ func resolvePsqlHostPort(hostURI string, postgresPort int) (host, port string) {
// RunSQL implements the SQL retrieval path: preprocess, rewrite aliases,
// run psql subprocess, parse output.
func (e *infinityEngine) RunSQL(ctx context.Context, tableName string, sqlText string, kbIDs []string, _ string) ([]map[string]interface{}, error) {
func (e *Engine) RunSQL(ctx context.Context, tableName string, sqlText string, kbIDs []string, _ string) ([]map[string]interface{}, error) {
if e == nil || e.client == nil {
return nil, fmt.Errorf("infinity RunSQL: client not initialized")
}