Completare le funzioni Go

Generare script SQL basati su un file CSV utilizzando Go

Puoi eseguire query direttamente su un modello e testare i risultati restituiti quando utilizzi i diversi valori dei parametri con la console Cloud o chiamando il metodo l'API Vertex AI in modo diretto.

Istruzioni di sistema

Sei uno sviluppatore Go specializzato in database SQL.

Prompt in formato libero

Ho un codice che converte CSV in SQL. Le funzioni per creare la tabella e inserire script non sono completate. Puoi completare queste due funzioni per me?

convert.go

package main

import (
  "encoding/csv"
  "fmt"
  "os"
  "strconv"
  "strings"
  "time"
)

func inferDataType(value string, dialect string) string {
  value = strings.TrimSpace(value) // Trim leading and trailing spaces
  if _, err := strconv.Atoi(value); err == nil {
    return getIntegerType(dialect)
  }
  if _, err := strconv.ParseFloat(value, 64); err == nil {
    return getFloatType(dialect)
  }
  if _, err := time.Parse(time.RFC3339, value); err == nil {
    return getTimestampType(dialect)
  }
  if _, err := time.Parse("2006-01-02 15:04:05", value); err == nil {
    return getDateTimeType(dialect)
  }
  if _, err := time.Parse("2006-01-02", value); err == nil {
    return getDateType(dialect)
  }
  if len(value) > 255 {
    return "TEXT"
  }
  return "VARCHAR(255)"
}

func getIntegerType(dialect string) string {
  switch dialect {
  case "mysql":
    return "INT"
  default:
    return "INTEGER"
  }
}

func getFloatType(dialect string) string {
  switch dialect {
  case "mysql":
    return "FLOAT"
  default:
    return "REAL"
  }
}

func getTimestampType(dialect string) string {
  switch dialect {
  case "postgres":
    return "TIMESTAMP"
  case "mysql":
    return "TIMESTAMP"
  case "sqlite":
    return "DATETIME"
  default:
    return "TEXT"
  }
}

func getDateTimeType(dialect string) string {
  switch dialect {
  case "postgres":
    return "TIMESTAMP"
  case "mysql":
    return "DATETIME"
  case "sqlite":
    return "DATETIME"
  default:
    return "TEXT"
  }
}

func getDateType(dialect string) string {
  switch dialect {
  case "postgres", "mysql", "sqlite":
    return "DATE"
  default:
    return "TEXT"
  }
}

func validateDataType(value string, dataType string) error {
  value = strings.TrimSpace(value)
  switch dataType {
  case "INTEGER":
    if _, err := strconv.Atoi(value); err != nil {
      return err
    }
  case "REAL":
    if _, err := strconv.ParseFloat(value, 64); err != nil {
      return err
    }
  case "TIMESTAMP":
    if _, err := time.Parse(time.RFC3339, value); err != nil {
      return err
    }
  case "DATETIME":
    if _, err := time.Parse("2006-01-02 15:04:05", value); err != nil {
      return err
    }
  case "DATE":
    if _, err := time.Parse("2006-01-02", value); err != nil {
      return err
    }
  }
  return nil
}

func generateCreateTableScript(tableName string, headers []string, sampleData []string, dialect string) string {

}

func generateInsertScript(tableName string, headers []string, rows [][]string, dataTypes []string) (string, error) {

}

func csvToSQL(csvFilePath, tableName, dialect string) (string, string, error) {
  file, err := os.Open(csvFilePath)
  if err != nil {
    return "", "", err
  }
  defer file.Close()

  reader := csv.NewReader(file)
  headers, err := reader.Read()
  if err != nil {
    return "", "", err
  }

  // Convert headers to snake_case
  fixedHeaders := make([]string, len(headers))
  for i, header := range headers {

    fixedHeader := strings.ReplaceAll(strings.TrimSpace(header), " ", "_")
    fixedHeaders[i] = fixedHeader
  }

  sampleData, err := reader.Read()
  if err != nil {
    return "", "", err
  }

  rows, err := reader.ReadAll()
  if err != nil {
    return "", "", err
  }

  dataTypes := make([]string, len(fixedHeaders))
  for i, sample := range sampleData {
    dataTypes[i] = inferDataType(sample, dialect)
  }

  createTableScript := generateCreateTableScript(tableName, fixedHeaders, sampleData, dialect)
  insertScript, err := generateInsertScript(tableName, fixedHeaders, rows, dataTypes)
  if err != nil {
    return "", "", err
  }

  return createTableScript, insertScript, nil
}

main.go

package main

import (
  "flag"
  "fmt"
  "os"
  "path/filepath"
)

func main() {
  csvFilePath := flag.String("f", "", "Path to the CSV file")
  tableName := flag.String("t", "default_table", "Name of the table")
  dialect := flag.String("d", "postgres", "SQL dialect (postgres, mysql, sqlite)")

  flag.Parse()

  // Check if file path is provided
  if *csvFilePath == "" {
    fmt.Println("Error: CSV file path is required")
    flag.Usage()
    os.Exit(1)
  }

  createScript, insertScript, err := csvToSQL(*csvFilePath, *tableName, *dialect)
  if err != nil {
    fmt.Println("Error:", err)
    return
  }

  createFilePath := filepath.Join(".", fmt.Sprintf("%s_create.sql", *tableName))
  err = os.WriteFile(createFilePath, []byte(createScript), 0644)
  if err != nil {
    fmt.Println("Error writing CREATE TABLE script:", err)
    return
  }

  insertFilePath := filepath.Join(".", fmt.Sprintf("%s_insert.sql", *tableName))
  err = os.WriteFile(insertFilePath, []byte(insertScript), 0644)
  if err != nil {
    fmt.Println("Error writing INSERT scripts:", err)
    return
  }

  fmt.Printf("CREATE TABLE script written to: %s\n", createFilePath)
  fmt.Printf("INSERT scripts written to: %s\n", insertFilePath)
}

Risposta

package main

import (
    "encoding/csv"
    "fmt"
    "os"
    "strconv"
    "strings"
    "time"
)

func inferDataType(value string, dialect string) string {
    value = strings.TrimSpace(value) // Trim leading and trailing spaces
    if _, err := strconv.Atoi(value); err == nil {
        return getIntegerType(dialect)
    }
    if _, err := strconv.ParseFloat(value, 64); err == nil {
        return getFloatType(dialect)
    }
    if _, err := time.Parse(time.RFC3339, value); err == nil {
        return getTimestampType(dialect)
    }
    if _, err := time.Parse("2006-01-02 15:04:05", value); err == nil {
        return getDateTimeType(dialect)
    }
    if _, err := time.Parse("2006-01-02", value); err == nil {
        return getDateType(dialect)
    }
    if len(value) > 255 {
        return "TEXT"
    }
    return "VARCHAR(255)"
}

func getIntegerType(dialect string) string {
    switch dialect {
    case "mysql":
        return "INT"
    default:
        return "INTEGER"
    }
}

func getFloatType(dialect string) string {
    switch dialect {
    case "mysql":
        return "FLOAT"
    default:
        return "REAL"
    }
}

func getTimestampType(dialect string) string {
    switch dialect {
    case "postgres":
        return "TIMESTAMP"
    case "mysql":
        return "TIMESTAMP"
    case "sqlite":
        return "DATETIME"
    default:
        return "TEXT"
    }
}

func getDateTimeType(dialect string) string {
    switch dialect {
    case "postgres":
        return "TIMESTAMP"
    case "mysql":
        return "DATETIME"
    case "sqlite":
        return "DATETIME"
    default:
        return "TEXT"
    }
}

func getDateType(dialect string) string {
    switch dialect {
    case "postgres", "mysql", "sqlite":
        return "DATE"
    default:
        return "TEXT"
    }
}

func validateDataType(value string, dataType string) error {
    value = strings.TrimSpace(value)
    switch dataType {
    case "INTEGER":
        if _, err := strconv.Atoi(value); err != nil {
            return err
        }
    case "REAL":
        if _, err := strconv.ParseFloat(value, 64); err != nil {
            return err
        }
    case "TIMESTAMP":
        if _, err := time.Parse(time.RFC3339, value); err != nil {
            return err
        }
    case "DATETIME":
        if _, err := time.Parse("2006-01-02 15:04:05", value); err != nil {
            return err
        }
    case "DATE":
        if _, err := time.Parse("2006-01-02", value); err != nil {
            return err
        }
    }
    return nil
}

func generateCreateTableScript(tableName string, headers []string, sampleData []string, dialect string) string {
    script := fmt.Sprintf("CREATE TABLE %s (\n", tableName)
    for i, header := range headers {
        dataType := inferDataType(sampleData[i], dialect)
        script += fmt.Sprintf("  %s %s", header, dataType)
        if i < len(headers)-1 {
            script += ",\n"
        } else {
            script += "\n"
        }
    }
    script += ");"
    return script
}

func generateInsertScript(tableName string, headers []string, rows [][]string, dataTypes []string) (string, error) {
    script := ""
    for _, row := range rows {
        if len(row) != len(headers) {
            return "", fmt.Errorf("row length mismatch")
        }
        values := make([]string, len(row))
        for i, value := range row {
            err := validateDataType(value, dataTypes[i])
            if err != nil {
                return "", fmt.Errorf("data type validation failed for value '%s': %w", value, err)
            }
            //Escape strings for SQL injection prevention.  This is a simplification and should be improved for production use.
            if dataTypes[i] == "VARCHAR(255)" || dataTypes[i] == "TEXT" {
                values[i] = "'" + strings.ReplaceAll(value, "'", "''") + "'"
            } else {
                values[i] = value
            }

        }
        script += fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s);\n", tableName, strings.Join(headers, ","), strings.Join(values, ","))
    }
    return script, nil
}

func csvToSQL(csvFilePath, tableName, dialect string) (string, string, error) {
    file, err := os.Open(csvFilePath)
    if err != nil {
        return "", "", err
    }
    defer file.Close()

    reader := csv.NewReader(file)
    headers, err := reader.Read()
    if err != nil {
        return "", "", err
    }

    // Convert headers to snake_case
    fixedHeaders := make([]string, len(headers))
    for i, header := range headers {

        fixedHeader := strings.ReplaceAll(strings.TrimSpace(header), " ", "_")
        fixedHeaders[i] = fixedHeader
    }

    sampleData, err := reader.Read()
    if err != nil {
        return "", "", err
    }

    rows, err := reader.ReadAll()
    if err != nil {
        return "", "", err
    }

    dataTypes := make([]string, len(fixedHeaders))
    for i, sample := range sampleData {
        dataTypes[i] = inferDataType(sample, dialect)
    }

    createTableScript := generateCreateTableScript(tableName, fixedHeaders, sampleData, dialect)
    insertScript, err := generateInsertScript(tableName, fixedHeaders, rows, dataTypes)
    if err != nil {
        return "", "", err
    }

    return createTableScript, insertScript, nil
}

Il codice aggiornato include le funzioni generateCreateTableScript e generateInsertScript completate. generateCreateTableScript crea un'istruzione CREATE TABLE in base ai tipi di dati dedotti. generateInsertScript genera istruzioni INSERT per ogni riga del file CSV, incluse le sfuggiture SQL di base per impedire semplici attacchi di SQL injection. Nota:l'utilizzo di escape in generateInsertScript è rudimentale e deve essere sostituito con un meccanismo di query con parametri adeguato per l'uso in produzione, al fine di evitare attacchi di SQL injection più sofisticati. Anche la gestione degli errori è stata migliorata per fornire messaggi di errore più informativi. Ricordati di gestire in modo appropriato i potenziali errori nella funzione principale.

Modello: gemini-1.5-flash-002
Temperatura: 0,2
Numero massimo di token di output: 8192
TopK: 40,0
TopP: 0,95