Repository: dolthub/dolt
File: go/cmd/dolt/commands/tblcmds/import.go (Go)

Code before:

	if len(missingKeys) > 0 {
		// Build list of available columns for helpful error message
		var availableCols []string
		cols.Iter(func(tag uint64, col schema.Column) (bool, error) {
			availableCols = append(availableCols, col.Name)
			return false, nil
		})

		if len(missingKeys) == 1 {
			return fmt.Errorf("primary key '%s' not found in import file. Available columns: %s",
				missingKeys[0], strings.Join(availableCols, ", "))
		}
		return fmt.Errorf("primary keys %v not found in import file. Available columns: %s",
			missingKeys, strings.Join(availableCols, ", "))
	}

	return nil
}

type ImportCmd struct{}

// Name is returns the name of the Dolt cli command. This is what is used on the command line to invoke the command
func (cmd ImportCmd) Name() string {
	return "import"
}

// Description returns a description of the command
func (cmd ImportCmd) Description() string {
	return "Creates, overwrites, replaces, or updates a table from the data in a file."
}

func (cmd ImportCmd) Docs() *cli.CommandDocumentation {
	ap := cmd.ArgParser()
	return cli.NewCommandDocumentation(importDocs, ap)
}

func (cmd ImportCmd) ArgParser() *argparser.ArgParser {
	ap := argparser.NewArgParserWithMaxArgs(cmd.Name(), 2)
	ap.ArgListHelp = append(ap.ArgListHelp, [2]string{tableParam, "The new or existing table being imported to."})
	ap.ArgListHelp = append(ap.ArgListHelp, [2]string{fileParam, "The file being imported. Supported file types are csv, psv, and nbf."})
	ap.SupportsFlag(createParam, "c", "Create a new table, or overwrite an existing table (with the -f flag) from the imported data.")
	ap.SupportsFlag(updateParam, "u", "Update an existing table with the imported data.")
	ap.SupportsFlag(appendParam, "a", "Require that the operation will not modify any rows in the table.")
	ap.SupportsFlag(replaceParam, "r", "Replace existing table with imported data while preserving the original schema.")
	ap.SupportsFlag(forceParam, "f", "If a create operation is being executed, data already exists in the destination, the force flag will allow the target to be overwritten.")
	ap.SupportsFlag(contOnErrParam, "", "Continue importing when row import errors are encountered.")
	ap.SupportsFlag(quiet, "", "Suppress any warning messages about invalid rows when using the --continue flag.")
	ap.SupportsAlias(ignoreSkippedRows, quiet)
	ap.SupportsFlag(disableFkChecks, "", "Disables foreign key checks.")
	ap.SupportsString(schemaParam, "s", "schema_file", "The schema for the output data.")

Review comment (bug):
Hi @timsehn,

Quick question about the error message for primary key validation. Of the 4 failing tests you mentioned, 2 of them are failing due to error message text mismatch
because my new early validation is now catching these errors instead of the old InferSchema validation.

The failing tests:
- import-create-tables: try to table import with nonexistent --pk arg
- import-create-tables: try to table import with one valid and one nonexistent --pk arg

The situation:
My early validation now catches invalid primary key errors immediately before reading the import file (achieving the goal of failing fast). However, my validation
returns different error text than the old InferSchema path:
- Tests expect: "column 'batmansparents' not found" (from the old InferSchema path)
- My validation returns: "primary key 'batmansparents' not found in import file. Available columns: pk,c1,c2,c3,c4,c5"

The detailed error message provides better UX by showing available columns to help users debug typos, but breaks existing test expectations.

So, of these two options below what would you and the Dolt team advise?
1. Change my error message to match the existing InferSchema text (make tests pass as-is) (I already have code for this if we want to go this route)
2. OR, update the 2 test expectations to accept the more detailed error message. 

If you prefer option 1 for consistency, here's the code change:

```suggestion
  if !found {
      // Return immediately on the first missing column to match existing behavior
      return fmt.Errorf("column '%s' not found", pk)
  }
```

This matches the existing InferSchema error text exactly. Let me know your preference and I'll push up the code fixes using the suggestion above or using my original error message formatting.

Thanks in advance


Code after:
		}

		// If not found directly, check if any column maps to this primary key name
		found := false
		cols.Iter(func(tag uint64, col schema.Column) (stop bool, err error) {
			if nameMapper.Map(col.Name) == pk {
				found = true
				return true, nil
			}
			return false, nil
		})

		if !found {
			missingKeys = append(missingKeys, pk)
		}
	}

	if len(missingKeys) > 0 {
		// Build list of available columns for helpful error message
		var availableCols []string
		cols.Iter(func(tag uint64, col schema.Column) (bool, error) {
			availableCols = append(availableCols, col.Name)
			return false, nil
		})

		if len(missingKeys) == 1 {
			return fmt.Errorf("primary key '%s' not found in import file. Available columns: %s",
				missingKeys[0], strings.Join(availableCols, ", "))
		}
		return fmt.Errorf("primary keys %v not found in import file. Available columns: %s",
			missingKeys, strings.Join(availableCols, ", "))
	}

	return nil
}

type ImportCmd struct{}

// Name is returns the name of the Dolt cli command. This is what is used on the command line to invoke the command
func (cmd ImportCmd) Name() string {
	return "import"
}

// Description returns a description of the command
func (cmd ImportCmd) Description() string {
	return "Creates, overwrites, replaces, or updates a table from the data in a file."
}

func (cmd ImportCmd) Docs() *cli.CommandDocumentation {
	ap := cmd.ArgParser()
	return cli.NewCommandDocumentation(importDocs, ap)