package stardb import ( "context" "database/sql" "fmt" "reflect" "strings" ) // BatchInsert performs batch insert operation // Usage: BatchInsert("users", []string{"name", "age"}, [][]interface{}{{"Alice", 25}, {"Bob", 30}}) func (s *StarDB) BatchInsert(tableName string, columns []string, values [][]interface{}) (sql.Result, error) { return s.batchInsert(nil, tableName, columns, values) } // BatchInsertContext performs batch insert with context func (s *StarDB) BatchInsertContext(ctx context.Context, tableName string, columns []string, values [][]interface{}) (sql.Result, error) { return s.batchInsert(ctx, tableName, columns, values) } // batchInsert is the internal implementation func (s *StarDB) batchInsert(ctx context.Context, tableName string, columns []string, values [][]interface{}) (sql.Result, error) { if len(values) == 0 { return nil, fmt.Errorf("no values to insert") } // Build placeholders: (?, ?), (?, ?), ... placeholderGroup := "(" + strings.Repeat("?, ", len(columns)-1) + "?)" placeholders := strings.Repeat(placeholderGroup+", ", len(values)-1) + placeholderGroup // Build SQL query := fmt.Sprintf("INSERT INTO %s (%s) VALUES %s", tableName, strings.Join(columns, ", "), placeholders) // Flatten values var args []interface{} for _, row := range values { args = append(args, row...) } return s.exec(ctx, query, args...) } // BatchInsertStructs performs batch insert using structs func (s *StarDB) BatchInsertStructs(tableName string, structs interface{}, autoIncrementFields ...string) (sql.Result, error) { return s.batchInsertStructs(nil, tableName, structs, autoIncrementFields...) } // BatchInsertStructsContext performs batch insert using structs with context func (s *StarDB) BatchInsertStructsContext(ctx context.Context, tableName string, structs interface{}, autoIncrementFields ...string) (sql.Result, error) { return s.batchInsertStructs(ctx, tableName, structs, autoIncrementFields...) } // batchInsertStructs is the internal implementation func (s *StarDB) batchInsertStructs(ctx context.Context, tableName string, structs interface{}, autoIncrementFields ...string) (sql.Result, error) { // Get slice of structs targetValue := reflect.ValueOf(structs) if targetValue.Kind() == reflect.Ptr { targetValue = targetValue.Elem() } if targetValue.Kind() != reflect.Slice && targetValue.Kind() != reflect.Array { return nil, fmt.Errorf("structs must be a slice or array") } if targetValue.Len() == 0 { return nil, fmt.Errorf("no structs to insert") } // Get field names from first struct firstStruct := targetValue.Index(0).Interface() fieldNames, err := getStructFieldNames(firstStruct, "db") if err != nil { return nil, err } // Filter out auto-increment fields var columns []string for _, fieldName := range fieldNames { isAutoIncrement := false for _, autoField := range autoIncrementFields { if fieldName == autoField { isAutoIncrement = true break } } if !isAutoIncrement { columns = append(columns, fieldName) } } // Extract values from all structs var values [][]interface{} for i := 0; i < targetValue.Len(); i++ { structVal := targetValue.Index(i).Interface() fieldValues, err := getStructFieldValues(structVal, "db") if err != nil { return nil, err } var row []interface{} for _, col := range columns { row = append(row, fieldValues[col]) } values = append(values, row) } return s.batchInsert(ctx, tableName, columns, values) }