This is an automated email from the ASF dual-hosted git repository.

laskoviymishka pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-go.git


The following commit(s) were added to refs/heads/main by this push:
     new c21d4b4e4 refactor(table)!: clarify path and DataFile replacement APIs 
(#2306)
c21d4b4e4 is described below

commit c21d4b4e473b12e1e5d4fb766a88384cd2bd9ed7
Author: Minh Vu <[email protected]>
AuthorDate: Sun Oct 25 10:11:09 2026 +0100

    refactor(table)!: clarify path and DataFile replacement APIs (#2306)
---
 table/branch_planning_test.go      |  8 ++--
 table/data_file_meta.go            |  2 +-
 table/data_file_meta_test.go       |  2 +-
 table/dv_rewrite_test.go           |  8 ++--
 table/rewrite_files.go             |  2 +-
 table/rewrite_files_test.go        |  4 +-
 table/table_test.go                | 96 +++++++++++++++++++-------------------
 table/transaction.go               | 27 ++++++-----
 table/transaction_internal_test.go |  8 ++--
 table/write_file_io_test.go        |  2 +-
 website/src/api.md                 |  2 +-
 website/src/feature-status.md      |  2 +-
 website/src/releases.md            |  2 +
 13 files changed, 86 insertions(+), 79 deletions(-)

diff --git a/table/branch_planning_test.go b/table/branch_planning_test.go
index d61b117d8..cb8667ac8 100644
--- a/table/branch_planning_test.go
+++ b/table/branch_planning_test.go
@@ -463,7 +463,7 @@ func TestBranchAddFilesDuplicateCheckUsesBranchHead(t 
*testing.T) {
 // A table written only through a branch has no main head, so a main-based plan
 // rejects the replace outright instead of performing it.
 func TestReplaceOnBranchOnlyTable(t *testing.T) {
-       t.Run("ReplaceDataFiles", func(t *testing.T) {
+       t.Run("ReplaceDataFilesByPath", func(t *testing.T) {
                tbl := newBranchPlanningTable(t, nil)
                tbl = appendRowsOnRef(t, tbl, branchPlanningRef, 1, 2)
                require.Nil(t, tbl.CurrentSnapshot(), "fixture must leave main 
without a head")
@@ -478,7 +478,7 @@ func TestReplaceOnBranchOnlyTable(t *testing.T) {
 
                txn, err := 
tbl.NewTransactionOnBranchWithError(branchPlanningRef)
                require.NoError(t, err)
-               require.NoError(t, txn.ReplaceDataFiles(t.Context(), original, 
[]string{replacement}, nil))
+               require.NoError(t, txn.ReplaceDataFilesByPath(t.Context(), 
original, []string{replacement}, nil))
                tbl, err = txn.Commit(t.Context())
                require.NoError(t, err)
 
@@ -486,7 +486,7 @@ func TestReplaceOnBranchOnlyTable(t *testing.T) {
                assert.Nil(t, tbl.CurrentSnapshot(), "replacing on the branch 
must not create a main head")
        })
 
-       t.Run("ReplaceDataFilesWithDataFiles", func(t *testing.T) {
+       t.Run("ReplaceDataFiles", func(t *testing.T) {
                tbl := newBranchPlanningTable(t, nil)
                staged := buildDataFile(t, 
tbl.Location()+"/data/branch-1.parquet")
 
@@ -500,7 +500,7 @@ func TestReplaceOnBranchOnlyTable(t *testing.T) {
                replacement := buildDataFile(t, 
tbl.Location()+"/data/branch-2.parquet")
                txn, err = 
tbl.NewTransactionOnBranchWithError(branchPlanningRef)
                require.NoError(t, err)
-               require.NoError(t, 
txn.ReplaceDataFilesWithDataFiles(t.Context(),
+               require.NoError(t, txn.ReplaceDataFiles(t.Context(),
                        []iceberg.DataFile{staged}, 
[]iceberg.DataFile{replacement}, nil))
                tbl, err = txn.Commit(t.Context())
                require.NoError(t, err)
diff --git a/table/data_file_meta.go b/table/data_file_meta.go
index 99a5fdff4..aabc710f0 100644
--- a/table/data_file_meta.go
+++ b/table/data_file_meta.go
@@ -119,7 +119,7 @@ type DataFileArgs struct {
        //   - [Transaction.AddDataFiles]: REQUIRED. These are 
externally-written
        //     files, so the library cannot fabricate row IDs for them; a nil
        //     first_row_id is rejected at commit time.
-       //   - [Transaction.ReplaceDataFilesWithDataFiles]: REQUIRED for the 
added
+       //   - [Transaction.ReplaceDataFiles]: REQUIRED for the added
        //     files, except when the caller opts into rewrite/compaction 
semantics
        //     (WithRewriteSemantics), where the manifest-list writer assigns 
it by
        //     inheritance and it may be left nil.
diff --git a/table/data_file_meta_test.go b/table/data_file_meta_test.go
index 9ca145ed8..572cd02f4 100644
--- a/table/data_file_meta_test.go
+++ b/table/data_file_meta_test.go
@@ -1171,7 +1171,7 @@ func 
TestDataFileFromMetadata_V3ReplaceDataFilesRequiresFirstRowID(t *testing.T)
        require.Nil(t, replacement.FirstRowID())
 
        tx = tbl.NewTransaction()
-       err = tx.ReplaceDataFilesWithDataFiles(t.Context(),
+       err = tx.ReplaceDataFiles(t.Context(),
                []iceberg.DataFile{initial}, []iceberg.DataFile{replacement}, 
nil)
        require.ErrorContains(t, err, "first_row_id")
        require.ErrorContains(t, err, "required for v3")
diff --git a/table/dv_rewrite_test.go b/table/dv_rewrite_test.go
index 0da507fc2..028f461b6 100644
--- a/table/dv_rewrite_test.go
+++ b/table/dv_rewrite_test.go
@@ -529,11 +529,11 @@ func TestRemovingDataFileRemovesItsUnnamedDV(t 
*testing.T) {
                {"RewriteFiles", func(ctx context.Context, tx 
*table.Transaction, dataB, dataC, _ iceberg.DataFile) error {
                        return 
tx.NewRewrite(nil).DeleteFile(dataB).AddDataFile(dataC).Commit(ctx)
                }},
-               {"ReplaceDataFilesWithDataFiles", func(ctx context.Context, tx 
*table.Transaction, dataB, dataC, _ iceberg.DataFile) error {
-                       return tx.ReplaceDataFilesWithDataFiles(ctx, 
[]iceberg.DataFile{dataB}, []iceberg.DataFile{dataC}, nil)
+               {"ReplaceDataFiles", func(ctx context.Context, tx 
*table.Transaction, dataB, dataC, _ iceberg.DataFile) error {
+                       return tx.ReplaceDataFiles(ctx, 
[]iceberg.DataFile{dataB}, []iceberg.DataFile{dataC}, nil)
                }},
-               {"ReplaceDataFiles", func(ctx context.Context, tx 
*table.Transaction, dataB, _, _ iceberg.DataFile) error {
-                       return tx.ReplaceDataFiles(ctx, 
[]string{dataB.FilePath()}, nil, nil)
+               {"ReplaceDataFilesByPath", func(ctx context.Context, tx 
*table.Transaction, dataB, _, _ iceberg.DataFile) error {
+                       return tx.ReplaceDataFilesByPath(ctx, 
[]string{dataB.FilePath()}, nil, nil)
                }},
                {"ReplaceFiles", func(ctx context.Context, tx 
*table.Transaction, dataB, dataC, eqDelete iceberg.DataFile) error {
                        return tx.ReplaceFiles(ctx, []iceberg.DataFile{dataB}, 
[]iceberg.DataFile{dataC}, []iceberg.DataFile{eqDelete}, nil)
diff --git a/table/rewrite_files.go b/table/rewrite_files.go
index c9d26b863..172510cc2 100644
--- a/table/rewrite_files.go
+++ b/table/rewrite_files.go
@@ -327,7 +327,7 @@ func (r *RewriteFiles) Commit(ctx context.Context) error {
                return fmt.Errorf("%w: rewrite must have at least one file 
change", ErrInvalidOperation)
        }
        // Adds-without-deletes would route through ReplaceFiles →
-       // ReplaceDataFilesWithDataFiles → AddDataFiles, an OpAppend
+       // ReplaceDataFiles → AddDataFiles, an OpAppend
        // producer that never reads cfg.rewriteSemantics. The snapshot
        // would be tagged append with no rewrite validator — silently
        // wrong for a rewrite. A pure delete-file expunge (only
diff --git a/table/rewrite_files_test.go b/table/rewrite_files_test.go
index 6c4e3e5f2..5b6d21d5d 100644
--- a/table/rewrite_files_test.go
+++ b/table/rewrite_files_test.go
@@ -408,7 +408,7 @@ func TestRewriteFiles_DeleteFile_RoutesByContentType(t 
*testing.T) {
        //
        //   Builder A — DeleteFile(strangerData): if routed correctly, the
        //   transaction has an empty deleteFilesToRemove slice and falls
-       //   through to ReplaceDataFilesWithDataFiles, which rejects with
+       //   through to ReplaceDataFiles, which rejects with
        //   "cannot delete files that do not belong to the table". A
        //   mis-route into deleteFilesToRemove would error with "cannot
        //   remove delete files that do not belong to the table" instead.
@@ -502,7 +502,7 @@ func TestAddFiles_ReAddsPathDeletedByRewrite(t *testing.T) {
 // TestRewriteFiles_RejectsAddsWithoutDataDeletes proves that staging
 // new data files with no data files to delete is rejected up front —
 // otherwise the chain would slip through ReplaceFiles →
-// ReplaceDataFilesWithDataFiles → AddDataFiles (an OpAppend producer)
+// ReplaceDataFiles → AddDataFiles (an OpAppend producer)
 // and silently tag the snapshot append instead of replace, with no
 // rewrite validator registered.
 func TestRewriteFiles_RejectsAddsWithoutDataDeletes(t *testing.T) {
diff --git a/table/table_test.go b/table/table_test.go
index a58f70b2a..c00672a4e 100644
--- a/table/table_test.go
+++ b/table/table_test.go
@@ -1111,7 +1111,7 @@ func (m *mockedCatalog) CommitTable(ctx context.Context, 
ident table.Identifier,
        return meta, "", nil
 }
 
-func (t *TableWritingTestSuite) TestReplaceDataFiles() {
+func (t *TableWritingTestSuite) TestReplaceDataFilesByPath() {
        fs := iceio.LocalFS{}
 
        files := make([]string, 0)
@@ -1169,7 +1169,7 @@ func (t *TableWritingTestSuite) TestReplaceDataFiles() {
        t.writeParquet(fs, combinedFilePath, combined)
 
        tx := tbl.NewTransaction()
-       t.Require().NoError(tx.ReplaceDataFiles(ctx, files[:2], 
[]string{combinedFilePath}, nil))
+       t.Require().NoError(tx.ReplaceDataFilesByPath(ctx, files[:2], 
[]string{combinedFilePath}, nil))
 
        staged, err := tx.StagedTable()
        t.Require().NoError(err)
@@ -1383,7 +1383,7 @@ func (t *TableWritingTestSuite) 
TestAddDataFilesAutoNameMapping() {
        }
 }
 
-func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesAutoNameMapping() {
+func (t *TableWritingTestSuite) TestReplaceDataFilesAutoNameMapping() {
        for _, tc := range []struct {
                name      string
                opts      []table.WriteOption
@@ -1416,7 +1416,7 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesAutoNameMapping
                        addFile := t.mustDataFile(*iceberg.UnpartitionedSpec, 
replacementPath, nil, 1, mustFileSize(t.T(), replacementPath))
 
                        tx = tbl.NewTransaction()
-                       
t.Require().NoError(tx.ReplaceDataFilesWithDataFiles(t.ctx, 
[]iceberg.DataFile{deleteFile}, []iceberg.DataFile{addFile}, nil, tc.opts...))
+                       t.Require().NoError(tx.ReplaceDataFiles(t.ctx, 
[]iceberg.DataFile{deleteFile}, []iceberg.DataFile{addFile}, nil, tc.opts...))
 
                        staged, err := tx.StagedTable()
                        t.Require().NoError(err)
@@ -1426,7 +1426,7 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesAutoNameMapping
        }
 }
 
-func (t *TableWritingTestSuite) TestReplaceDataFilesWithDataFiles() {
+func (t *TableWritingTestSuite) TestReplaceDataFiles() {
        ident := table.Identifier{"default", 
"replace_data_files_with_datafiles_v" + strconv.Itoa(t.formatVersion)}
        tbl := t.createTable(ident, t.formatVersion, 
*iceberg.UnpartitionedSpec, t.tableSchema)
 
@@ -1452,7 +1452,7 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFiles() {
        addFile := t.mustDataFile(*iceberg.UnpartitionedSpec, replacementPath, 
nil, 1, mustFileSize(t.T(), replacementPath))
 
        tx = tbl.NewTransaction()
-       t.Require().NoError(tx.ReplaceDataFilesWithDataFiles(t.ctx, 
deleteFiles, []iceberg.DataFile{addFile}, nil))
+       t.Require().NoError(tx.ReplaceDataFiles(t.ctx, deleteFiles, 
[]iceberg.DataFile{addFile}, nil))
 
        staged, err := tx.StagedTable()
        t.Require().NoError(err)
@@ -1461,7 +1461,7 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFiles() {
        t.Equal("2", 
staged.CurrentSnapshot().Summary.Properties["deleted-data-files"])
 }
 
-func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesDoesNotCarryEmptyManifests() {
+func (t *TableWritingTestSuite) 
TestReplaceDataFilesDoesNotCarryEmptyManifests() {
        ident := table.Identifier{"default", 
"replace_data_files_drops_empty_manifests_v" + strconv.Itoa(t.formatVersion)}
        tbl := t.createTable(ident, t.formatVersion, 
*iceberg.UnpartitionedSpec, t.tableSchema)
 
@@ -1482,7 +1482,7 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesDoesNotCarryEmp
        for i := 1; i <= 5; i++ {
                next := writeDataFile(fmt.Sprintf("data-%d", i))
                tx = tbl.NewTransaction()
-               t.Require().NoError(tx.ReplaceDataFilesWithDataFiles(t.ctx, 
[]iceberg.DataFile{current}, []iceberg.DataFile{next}, nil))
+               t.Require().NoError(tx.ReplaceDataFiles(t.ctx, 
[]iceberg.DataFile{current}, []iceberg.DataFile{next}, nil))
                tbl, err = tx.Commit(t.ctx)
                t.Require().NoError(err)
                current = next
@@ -1510,7 +1510,7 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesDoesNotCarryEmp
        t.Equal(1, emptyCurrentManifests)
 }
 
-func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesValidatesPartitionSpecID() {
+func (t *TableWritingTestSuite) TestReplaceDataFilesValidatesPartitionSpecID() 
{
        ident := table.Identifier{"default", 
"replace_data_files_with_datafiles_spec_validation_v" + 
strconv.Itoa(t.formatVersion)}
        spec := iceberg.NewPartitionSpec(
                iceberg.PartitionField{SourceIDs: []int{4}, FieldID: 1000, 
Transform: iceberg.IdentityTransform{}, Name: "baz"},
@@ -1535,12 +1535,12 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesValidatesPartit
                map[int]any{1000: int32(123)}, 1, 1)
 
        tx = tbl.NewTransaction()
-       err = tx.ReplaceDataFilesWithDataFiles(t.ctx, 
[]iceberg.DataFile{deleteFile}, []iceberg.DataFile{addFile}, nil)
+       err = tx.ReplaceDataFiles(t.ctx, []iceberg.DataFile{deleteFile}, 
[]iceberg.DataFile{addFile}, nil)
        t.Error(err)
        t.ErrorContains(err, "unregistered partition spec id 999")
 }
 
-func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesValidatesPartitionData() {
+func (t *TableWritingTestSuite) TestReplaceDataFilesValidatesPartitionData() {
        ident := table.Identifier{"default", 
"replace_data_files_with_datafiles_partition_validation_v" + 
strconv.Itoa(t.formatVersion)}
        spec := iceberg.NewPartitionSpec(
                iceberg.PartitionField{SourceIDs: []int{4}, FieldID: 1000, 
Transform: iceberg.IdentityTransform{}, Name: "baz"},
@@ -1561,7 +1561,7 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesValidatesPartit
                map[int]any{}, 1, 1)
 
        tx = tbl.NewTransaction()
-       err = tx.ReplaceDataFilesWithDataFiles(t.ctx, 
[]iceberg.DataFile{deleteFile}, []iceberg.DataFile{addFile}, nil)
+       err = tx.ReplaceDataFiles(t.ctx, []iceberg.DataFile{deleteFile}, 
[]iceberg.DataFile{addFile}, nil)
        t.Error(err)
        t.ErrorContains(err, "missing partition value")
 }
@@ -1675,10 +1675,10 @@ func (t *TableWritingTestSuite) 
TestAddDataFilesEmptySlice() {
 }
 
 // ============================================================================
-// ReplaceDataFilesWithDataFiles Error Path Tests
+// ReplaceDataFiles Error Path Tests
 // ============================================================================
 
-func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesDuplicateAddPaths() {
+func (t *TableWritingTestSuite) TestReplaceDataFilesDuplicateAddPaths() {
        ident := table.Identifier{"default", "replace_data_files_dup_add_v" + 
strconv.Itoa(t.formatVersion)}
        tbl := t.createTable(ident, t.formatVersion, 
*iceberg.UnpartitionedSpec, t.tableSchema)
 
@@ -1695,12 +1695,12 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesDuplicateAddPat
                fmt.Sprintf("%s/replace_data_files_dup_add_v%d/new.parquet", 
t.location, t.formatVersion), nil, 1, 100)
 
        tx = tbl.NewTransaction()
-       err = tx.ReplaceDataFilesWithDataFiles(t.ctx, 
[]iceberg.DataFile{deleteFile}, []iceberg.DataFile{addFile, addFile}, nil)
+       err = tx.ReplaceDataFiles(t.ctx, []iceberg.DataFile{deleteFile}, 
[]iceberg.DataFile{addFile, addFile}, nil)
        t.Error(err)
-       t.ErrorContains(err, "add data file paths must be unique for 
ReplaceDataFilesWithDataFiles")
+       t.ErrorContains(err, "add data file paths must be unique for 
ReplaceDataFiles")
 }
 
-func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesDuplicateDeletePaths() {
+func (t *TableWritingTestSuite) TestReplaceDataFilesDuplicateDeletePaths() {
        ident := table.Identifier{"default", "replace_data_files_dup_del_v" + 
strconv.Itoa(t.formatVersion)}
        tbl := t.createTable(ident, t.formatVersion, 
*iceberg.UnpartitionedSpec, t.tableSchema)
 
@@ -1717,12 +1717,12 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesDuplicateDelete
                fmt.Sprintf("%s/replace_data_files_dup_del_v%d/new.parquet", 
t.location, t.formatVersion), nil, 1, 100)
 
        tx = tbl.NewTransaction()
-       err = tx.ReplaceDataFilesWithDataFiles(t.ctx, 
[]iceberg.DataFile{deleteFile, deleteFile}, []iceberg.DataFile{addFile}, nil)
+       err = tx.ReplaceDataFiles(t.ctx, []iceberg.DataFile{deleteFile, 
deleteFile}, []iceberg.DataFile{addFile}, nil)
        t.Error(err)
-       t.ErrorContains(err, "delete data file paths must be unique for 
ReplaceDataFilesWithDataFiles")
+       t.ErrorContains(err, "delete data file paths must be unique for 
ReplaceDataFiles")
 }
 
-func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesAddAlreadyReferenced() {
+func (t *TableWritingTestSuite) TestReplaceDataFilesAddAlreadyReferenced() {
        ident := table.Identifier{"default", "replace_data_files_add_ref_v" + 
strconv.Itoa(t.formatVersion)}
        tbl := t.createTable(ident, t.formatVersion, 
*iceberg.UnpartitionedSpec, t.tableSchema)
 
@@ -1740,12 +1740,12 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesAddAlreadyRefer
        addFile := t.mustDataFile(*iceberg.UnpartitionedSpec, existingPath2, 
nil, 1, mustFileSize(t.T(), existingPath2))
 
        tx = tbl.NewTransaction()
-       err = tx.ReplaceDataFilesWithDataFiles(t.ctx, 
[]iceberg.DataFile{deleteFile}, []iceberg.DataFile{addFile}, nil)
+       err = tx.ReplaceDataFiles(t.ctx, []iceberg.DataFile{deleteFile}, 
[]iceberg.DataFile{addFile}, nil)
        t.Error(err)
        t.ErrorContains(err, "cannot add files that are already referenced by 
table")
 }
 
-func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesDeleteNotInTable() {
+func (t *TableWritingTestSuite) TestReplaceDataFilesDeleteNotInTable() {
        ident := table.Identifier{"default", 
"replace_data_files_del_not_found_v" + strconv.Itoa(t.formatVersion)}
        tbl := t.createTable(ident, t.formatVersion, 
*iceberg.UnpartitionedSpec, t.tableSchema)
 
@@ -1763,12 +1763,12 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesDeleteNotInTabl
                
fmt.Sprintf("%s/replace_data_files_del_not_found_v%d/new.parquet", t.location, 
t.formatVersion), nil, 1, 100)
 
        tx = tbl.NewTransaction()
-       err = tx.ReplaceDataFilesWithDataFiles(t.ctx, 
[]iceberg.DataFile{nonExistentFile}, []iceberg.DataFile{addFile}, nil)
+       err = tx.ReplaceDataFiles(t.ctx, []iceberg.DataFile{nonExistentFile}, 
[]iceberg.DataFile{addFile}, nil)
        t.Error(err)
        t.ErrorContains(err, "cannot delete files that do not belong to the 
table")
 }
 
-func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesNilDeleteFile() {
+func (t *TableWritingTestSuite) TestReplaceDataFilesNilDeleteFile() {
        ident := table.Identifier{"default", "replace_data_files_nil_del_v" + 
strconv.Itoa(t.formatVersion)}
        tbl := t.createTable(ident, t.formatVersion, 
*iceberg.UnpartitionedSpec, t.tableSchema)
 
@@ -1784,12 +1784,12 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesNilDeleteFile()
                fmt.Sprintf("%s/replace_data_files_nil_del_v%d/new.parquet", 
t.location, t.formatVersion), nil, 1, 100)
 
        tx = tbl.NewTransaction()
-       err = tx.ReplaceDataFilesWithDataFiles(t.ctx, []iceberg.DataFile{nil}, 
[]iceberg.DataFile{addFile}, nil)
+       err = tx.ReplaceDataFiles(t.ctx, []iceberg.DataFile{nil}, 
[]iceberg.DataFile{addFile}, nil)
        t.Error(err)
        t.ErrorContains(err, "nil data file at index 0")
 }
 
-func (t *TableWritingTestSuite) TestReplaceDataFilesWithDataFilesNilAddFile() {
+func (t *TableWritingTestSuite) TestReplaceDataFilesNilAddFile() {
        ident := table.Identifier{"default", "replace_data_files_nil_add_v" + 
strconv.Itoa(t.formatVersion)}
        tbl := t.createTable(ident, t.formatVersion, 
*iceberg.UnpartitionedSpec, t.tableSchema)
 
@@ -1804,12 +1804,12 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesNilAddFile() {
        deleteFile := t.mustDataFile(*iceberg.UnpartitionedSpec, existingPath, 
nil, 1, mustFileSize(t.T(), existingPath))
 
        tx = tbl.NewTransaction()
-       err = tx.ReplaceDataFilesWithDataFiles(t.ctx, 
[]iceberg.DataFile{deleteFile}, []iceberg.DataFile{nil}, nil)
+       err = tx.ReplaceDataFiles(t.ctx, []iceberg.DataFile{deleteFile}, 
[]iceberg.DataFile{nil}, nil)
        t.Error(err)
        t.ErrorContains(err, "nil data file at index 0")
 }
 
-func (t *TableWritingTestSuite) TestReplaceDataFilesWithDataFilesNoSnapshot() {
+func (t *TableWritingTestSuite) TestReplaceDataFilesNoSnapshot() {
        ident := table.Identifier{"default", "replace_data_files_no_snapshot_v" 
+ strconv.Itoa(t.formatVersion)}
        tbl := t.createTable(ident, t.formatVersion, 
*iceberg.UnpartitionedSpec, t.tableSchema)
 
@@ -1819,12 +1819,12 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesNoSnapshot() {
                
fmt.Sprintf("%s/replace_data_files_no_snapshot_v%d/add.parquet", t.location, 
t.formatVersion), nil, 1, 100)
 
        tx := tbl.NewTransaction()
-       err := tx.ReplaceDataFilesWithDataFiles(t.ctx, 
[]iceberg.DataFile{deleteFile}, []iceberg.DataFile{addFile}, nil)
+       err := tx.ReplaceDataFiles(t.ctx, []iceberg.DataFile{deleteFile}, 
[]iceberg.DataFile{addFile}, nil)
        t.Error(err)
        t.ErrorContains(err, "cannot replace files in a table without an 
existing snapshot")
 }
 
-func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesInvalidAddContentType() {
+func (t *TableWritingTestSuite) TestReplaceDataFilesInvalidAddContentType() {
        ident := table.Identifier{"default", 
"replace_data_files_invalid_add_content_v" + strconv.Itoa(t.formatVersion)}
        tbl := t.createTable(ident, t.formatVersion, 
*iceberg.UnpartitionedSpec, t.tableSchema)
 
@@ -1845,17 +1845,17 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesInvalidAddConte
        invalidAddFile := builder.Build()
 
        tx = tbl.NewTransaction()
-       err = tx.ReplaceDataFilesWithDataFiles(t.ctx, 
[]iceberg.DataFile{deleteFile}, []iceberg.DataFile{invalidAddFile}, nil)
+       err = tx.ReplaceDataFiles(t.ctx, []iceberg.DataFile{deleteFile}, 
[]iceberg.DataFile{invalidAddFile}, nil)
        t.Error(err)
        t.ErrorContains(err, "adding files other than data files is not yet 
implemented")
 }
 
-func (t *TableWritingTestSuite) TestReplaceDataFilesWithDataFilesEmptyBoth() {
+func (t *TableWritingTestSuite) TestReplaceDataFilesEmptyBoth() {
        ident := table.Identifier{"default", "replace_data_files_empty_both_v" 
+ strconv.Itoa(t.formatVersion)}
        tbl := t.createTable(ident, t.formatVersion, 
*iceberg.UnpartitionedSpec, t.tableSchema)
 
        tx := tbl.NewTransaction()
-       err := tx.ReplaceDataFilesWithDataFiles(t.ctx, []iceberg.DataFile{}, 
[]iceberg.DataFile{}, nil)
+       err := tx.ReplaceDataFiles(t.ctx, []iceberg.DataFile{}, 
[]iceberg.DataFile{}, nil)
        t.NoError(err)
 
        staged, err := tx.StagedTable()
@@ -1863,7 +1863,7 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesEmptyBoth() {
        t.Nil(staged.CurrentSnapshot())
 }
 
-func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesDelegatesToAddDataFiles() {
+func (t *TableWritingTestSuite) TestReplaceDataFilesDelegatesToAddDataFiles() {
        ident := table.Identifier{"default", "replace_data_files_delegate_v" + 
strconv.Itoa(t.formatVersion)}
        tbl := t.createTable(ident, t.formatVersion, 
*iceberg.UnpartitionedSpec, t.tableSchema)
 
@@ -1873,7 +1873,7 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesDelegatesToAddD
        addFile := t.mustDataFile(*iceberg.UnpartitionedSpec, filePath, nil, 1, 
mustFileSize(t.T(), filePath))
 
        tx := tbl.NewTransaction()
-       t.Require().NoError(tx.ReplaceDataFilesWithDataFiles(t.ctx, 
[]iceberg.DataFile{}, []iceberg.DataFile{addFile}, nil))
+       t.Require().NoError(tx.ReplaceDataFiles(t.ctx, []iceberg.DataFile{}, 
[]iceberg.DataFile{addFile}, nil))
 
        staged, err := tx.StagedTable()
        t.Require().NoError(err)
@@ -1882,10 +1882,10 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesWithDataFilesDelegatesToAddD
 }
 
 // ============================================================================
-// ReplaceDataFiles (string paths) Error Path Tests
+// ReplaceDataFilesByPath (string paths) Error Path Tests
 // ============================================================================
 
-func (t *TableWritingTestSuite) TestReplaceDataFilesDuplicateDeletePaths() {
+func (t *TableWritingTestSuite) 
TestReplaceDataFilesByPathDuplicateDeletePaths() {
        ident := table.Identifier{"default", 
"replace_data_files_dup_del_paths_v" + strconv.Itoa(t.formatVersion)}
        tbl := t.createTable(ident, t.formatVersion, 
*iceberg.UnpartitionedSpec, t.tableSchema)
 
@@ -1901,12 +1901,12 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesDuplicateDeletePaths() {
        t.writeParquet(mustFS(t.T(), tbl).(iceio.WriteFileIO), newPath, 
t.arrTbl)
 
        tx = tbl.NewTransaction()
-       err = tx.ReplaceDataFiles(t.ctx, []string{existingPath, existingPath}, 
[]string{newPath}, nil)
+       err = tx.ReplaceDataFilesByPath(t.ctx, []string{existingPath, 
existingPath}, []string{newPath}, nil)
        t.Error(err)
-       t.ErrorContains(err, "delete file paths must be unique for 
ReplaceDataFiles")
+       t.ErrorContains(err, "delete file paths must be unique for 
ReplaceDataFilesByPath")
 }
 
-func (t *TableWritingTestSuite) TestReplaceDataFilesDuplicateAddPaths() {
+func (t *TableWritingTestSuite) TestReplaceDataFilesByPathDuplicateAddPaths() {
        ident := table.Identifier{"default", 
"replace_data_files_dup_add_paths_v" + strconv.Itoa(t.formatVersion)}
        tbl := t.createTable(ident, t.formatVersion, 
*iceberg.UnpartitionedSpec, t.tableSchema)
 
@@ -1922,12 +1922,12 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesDuplicateAddPaths() {
        t.writeParquet(mustFS(t.T(), tbl).(iceio.WriteFileIO), newPath, 
t.arrTbl)
 
        tx = tbl.NewTransaction()
-       err = tx.ReplaceDataFiles(t.ctx, []string{existingPath}, 
[]string{newPath, newPath}, nil)
+       err = tx.ReplaceDataFilesByPath(t.ctx, []string{existingPath}, 
[]string{newPath, newPath}, nil)
        t.Error(err)
-       t.ErrorContains(err, "add file paths must be unique for 
ReplaceDataFiles")
+       t.ErrorContains(err, "add file paths must be unique for 
ReplaceDataFilesByPath")
 }
 
-func (t *TableWritingTestSuite) TestReplaceDataFilesAddAlreadyReferenced() {
+func (t *TableWritingTestSuite) 
TestReplaceDataFilesByPathAddAlreadyReferenced() {
        ident := table.Identifier{"default", 
"replace_data_files_add_already_ref_v" + strconv.Itoa(t.formatVersion)}
        tbl := t.createTable(ident, t.formatVersion, 
*iceberg.UnpartitionedSpec, t.tableSchema)
 
@@ -1942,12 +1942,12 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesAddAlreadyReferenced() {
        t.Require().NoError(err)
 
        tx = tbl.NewTransaction()
-       err = tx.ReplaceDataFiles(t.ctx, []string{existingPath1}, 
[]string{existingPath2}, nil)
+       err = tx.ReplaceDataFilesByPath(t.ctx, []string{existingPath1}, 
[]string{existingPath2}, nil)
        t.Error(err)
        t.ErrorContains(err, "cannot add files that are already referenced by 
table")
 }
 
-func (t *TableWritingTestSuite) TestReplaceDataFilesDeleteNotInTable() {
+func (t *TableWritingTestSuite) TestReplaceDataFilesByPathDeleteNotInTable() {
        ident := table.Identifier{"default", 
"replace_data_files_del_not_in_table_v" + strconv.Itoa(t.formatVersion)}
        tbl := t.createTable(ident, t.formatVersion, 
*iceberg.UnpartitionedSpec, t.tableSchema)
 
@@ -1965,17 +1965,17 @@ func (t *TableWritingTestSuite) 
TestReplaceDataFilesDeleteNotInTable() {
        nonExistentPath := 
fmt.Sprintf("%s/replace_data_files_del_not_in_table_v%d/nonexistent.parquet", 
t.location, t.formatVersion)
 
        tx = tbl.NewTransaction()
-       err = tx.ReplaceDataFiles(t.ctx, []string{nonExistentPath}, 
[]string{newPath}, nil)
+       err = tx.ReplaceDataFilesByPath(t.ctx, []string{nonExistentPath}, 
[]string{newPath}, nil)
        t.Error(err)
        t.ErrorContains(err, "cannot delete files that do not belong to the 
table")
 }
 
-func (t *TableWritingTestSuite) TestReplaceDataFilesNoSnapshot() {
+func (t *TableWritingTestSuite) TestReplaceDataFilesByPathNoSnapshot() {
        ident := table.Identifier{"default", 
"replace_data_files_no_snapshot_paths_v" + strconv.Itoa(t.formatVersion)}
        tbl := t.createTable(ident, t.formatVersion, 
*iceberg.UnpartitionedSpec, t.tableSchema)
 
        tx := tbl.NewTransaction()
-       err := tx.ReplaceDataFiles(t.ctx, []string{"delete.parquet"}, 
[]string{"add.parquet"}, nil)
+       err := tx.ReplaceDataFilesByPath(t.ctx, []string{"delete.parquet"}, 
[]string{"add.parquet"}, nil)
        t.Error(err)
        t.ErrorContains(err, "cannot replace files in a table without an 
existing snapshot")
 }
diff --git a/table/transaction.go b/table/transaction.go
index 2faa2ec01..e8369e6f9 100644
--- a/table/transaction.go
+++ b/table/transaction.go
@@ -927,7 +927,10 @@ func (t *Transaction) Append(ctx context.Context, rdr 
array.RecordReader, snapsh
        return t.apply(updates, reqs)
 }
 
-// ReplaceFiles is actually just an overwrite operation with multiple
+// ReplaceDataFilesByPath replaces data files identified by their storage 
paths.
+// Unlike ReplaceDataFiles, it loads file metadata as needed.
+//
+// It is actually an overwrite operation with multiple
 // files deleted and added.
 //
 // TODO: technically, this could be a REPLACE operation but we aren't 
performing
@@ -937,7 +940,7 @@ func (t *Transaction) Append(ctx context.Context, rdr 
array.RecordReader, snapsh
 // For now, we'll keep using an overwrite operation.
 //
 // On v3 a removed data file's live deletion vector is removed with it.
-func (t *Transaction) ReplaceDataFiles(ctx context.Context, filesToDelete, 
filesToAdd []string, snapshotProps iceberg.Properties) error {
+func (t *Transaction) ReplaceDataFilesByPath(ctx context.Context, 
filesToDelete, filesToAdd []string, snapshotProps iceberg.Properties) error {
        meta, err := t.txnMeta()
        if err != nil {
                return err
@@ -962,11 +965,11 @@ func (t *Transaction) ReplaceDataFiles(ctx 
context.Context, filesToDelete, files
        }
 
        if len(setToDelete) != len(filesToDelete) {
-               return errors.New("delete file paths must be unique for 
ReplaceDataFiles")
+               return errors.New("delete file paths must be unique for 
ReplaceDataFilesByPath")
        }
 
        if len(setToAdd) != len(filesToAdd) {
-               return errors.New("add file paths must be unique for 
ReplaceDataFiles")
+               return errors.New("add file paths must be unique for 
ReplaceDataFilesByPath")
        }
 
        s := t.planningSnapshot(meta)
@@ -1508,7 +1511,7 @@ func withDataSequenceNumber(seq int64) WriteOption {
 
 // WithoutAutoNameMapping disables the automatic setting of the schema name
 // mapping in table properties. By default, methods like 
[Transaction.AddDataFiles]
-// and [Transaction.ReplaceDataFilesWithDataFiles] will set the name mapping if
+// and [Transaction.ReplaceDataFiles] will set the name mapping if
 // one does not already exist. This option is useful when working with catalogs
 // (such as Databricks Unity Catalog) that reject the name mapping property.
 func WithoutAutoNameMapping() WriteOption {
@@ -1644,7 +1647,7 @@ func (t *Transaction) AddDataFiles(ctx context.Context, 
dataFiles []iceberg.Data
        return t.apply(updates, reqs)
 }
 
-// ReplaceDataFilesWithDataFiles replaces files using pre-built DataFile 
objects.
+// ReplaceDataFiles replaces files using pre-built DataFile objects.
 // This avoids scanning files to extract schema and statistics - the caller 
provides
 // DataFile objects directly with all required metadata.
 //
@@ -1668,7 +1671,7 @@ func (t *Transaction) AddDataFiles(ctx context.Context, 
dataFiles []iceberg.Data
 //   - Files are written via a separate I/O path and metadata is already known
 //   - Avoiding file scanning improves performance or reliability
 //   - Working with storage systems where immediate file reads may be 
unreliable
-func (t *Transaction) ReplaceDataFilesWithDataFiles(ctx context.Context, 
filesToDelete, filesToAdd []iceberg.DataFile, snapshotProps iceberg.Properties, 
opts ...WriteOption) error {
+func (t *Transaction) ReplaceDataFiles(ctx context.Context, filesToDelete, 
filesToAdd []iceberg.DataFile, snapshotProps iceberg.Properties, opts 
...WriteOption) error {
        meta, err := t.txnMeta()
        if err != nil {
                return err
@@ -1686,7 +1689,7 @@ func (t *Transaction) ReplaceDataFilesWithDataFiles(ctx 
context.Context, filesTo
                o(&cfg)
        }
 
-       setToAdd, err := t.validateDataFilesToAdd(filesToAdd, 
"ReplaceDataFilesWithDataFiles", !cfg.rewriteSemantics)
+       setToAdd, err := t.validateDataFilesToAdd(filesToAdd, 
"ReplaceDataFiles", !cfg.rewriteSemantics)
        if err != nil {
                return err
        }
@@ -1694,16 +1697,16 @@ func (t *Transaction) ReplaceDataFilesWithDataFiles(ctx 
context.Context, filesTo
        setToDelete := make(map[string]struct{}, len(filesToDelete))
        for i, df := range filesToDelete {
                if df == nil {
-                       return fmt.Errorf("nil data file at index %d for 
ReplaceDataFilesWithDataFiles", i)
+                       return fmt.Errorf("nil data file at index %d for 
ReplaceDataFiles", i)
                }
 
                path := df.FilePath()
                if path == "" {
-                       return errors.New("delete data file paths must be 
non-empty for ReplaceDataFilesWithDataFiles")
+                       return errors.New("delete data file paths must be 
non-empty for ReplaceDataFiles")
                }
 
                if _, ok := setToDelete[path]; ok {
-                       return errors.New("delete data file paths must be 
unique for ReplaceDataFilesWithDataFiles")
+                       return errors.New("delete data file paths must be 
unique for ReplaceDataFiles")
                }
                setToDelete[path] = struct{}{}
        }
@@ -1843,7 +1846,7 @@ func (t *Transaction) replaceFiles(ctx context.Context, 
dataFilesToDelete, dataF
 
        // Delegate data file replacement to existing logic.
        if len(deleteFilesToRemove) == 0 && len(autoDeleteFilesToRemove) == 0 
&& len(deleteFilesToAdd) == 0 {
-               return t.ReplaceDataFilesWithDataFiles(ctx, dataFilesToDelete, 
dataFilesToAdd, snapshotProps, opts...)
+               return t.ReplaceDataFiles(ctx, dataFilesToDelete, 
dataFilesToAdd, snapshotProps, opts...)
        }
        if len(deleteFilesToAdd) > 0 && len(deleteFilesToRemove) == 0 {
                return fmt.Errorf("%w: adding delete files requires replacing 
at least one existing delete file",
diff --git a/table/transaction_internal_test.go 
b/table/transaction_internal_test.go
index 4a26c07b1..0b09ed835 100644
--- a/table/transaction_internal_test.go
+++ b/table/transaction_internal_test.go
@@ -1174,9 +1174,11 @@ func 
TestTransactionEntryPointsRejectNilAndBrokenTransaction(t *testing.T) {
                {"Append", func(txn *Transaction) error { return 
txn.Append(ctx, nil, nil) }},
                {"AddDataFiles", func(txn *Transaction) error { return 
txn.AddDataFiles(ctx, []iceberg.DataFile{dataFile}, nil) }},
                {"AddFiles", func(txn *Transaction) error { return 
txn.AddFiles(ctx, []string{"file://a.parquet"}, nil, false) }},
-               {"ReplaceDataFiles", func(txn *Transaction) error { return 
txn.ReplaceDataFiles(ctx, []string{"a"}, []string{"b"}, nil) }},
-               {"ReplaceDataFilesWithDataFiles", func(txn *Transaction) error {
-                       return txn.ReplaceDataFilesWithDataFiles(ctx, 
[]iceberg.DataFile{dataFile}, nil, nil)
+               {"ReplaceDataFilesByPath", func(txn *Transaction) error {
+                       return txn.ReplaceDataFilesByPath(ctx, []string{"a"}, 
[]string{"b"}, nil)
+               }},
+               {"ReplaceDataFiles", func(txn *Transaction) error {
+                       return txn.ReplaceDataFiles(ctx, 
[]iceberg.DataFile{dataFile}, nil, nil)
                }},
                {"ReplaceFiles", func(txn *Transaction) error {
                        return txn.ReplaceFiles(ctx, 
[]iceberg.DataFile{dataFile}, nil, []iceberg.DataFile{dataFile}, nil)
diff --git a/table/write_file_io_test.go b/table/write_file_io_test.go
index 3acd52a91..13e3af85b 100644
--- a/table/write_file_io_test.go
+++ b/table/write_file_io_test.go
@@ -150,7 +150,7 @@ func TestWritePathsReturnErrorForReadOnlyIO(t *testing.T) {
                {
                        name: "replace data files with data files add-only 
path",
                        run: func(ctx context.Context, tbl *Table) error {
-                               return 
tbl.NewTransaction().ReplaceDataFilesWithDataFiles(ctx, nil, []iceberg.DataFile{
+                               return 
tbl.NewTransaction().ReplaceDataFiles(ctx, nil, []iceberg.DataFile{
                                        newWriteIORequiredDataFileWithPath(t, 
"file:///tmp/read-only-write/replace-data-files-add.parquet"),
                                }, nil)
                        },
diff --git a/website/src/api.md b/website/src/api.md
index 0f00ddd37..b1c62e370 100644
--- a/website/src/api.md
+++ b/website/src/api.md
@@ -362,7 +362,7 @@ if err != nil { /* ... */ }
 newTbl, err := txn.Commit(ctx)
 ```
 
-`ReplaceDataFiles(ctx, filesToDelete, filesToAdd, snapshotProps)` and 
`ReplaceDataFilesWithDataFiles(ctx, filesToDelete, dataFilesToAdd, 
snapshotProps, opts...)` are also available on `*Transaction` for swapping 
files atomically.
+`ReplaceDataFilesByPath(ctx, filesToDelete, filesToAdd, snapshotProps)` and 
`ReplaceDataFiles(ctx, filesToDelete, dataFilesToAdd, snapshotProps, opts...)` 
are also available on `*Transaction` for swapping files atomically.
 
 ### Transactions
 
diff --git a/website/src/feature-status.md b/website/src/feature-status.md
index 5802da8e0..9021bcbbf 100644
--- a/website/src/feature-status.md
+++ b/website/src/feature-status.md
@@ -39,7 +39,7 @@ All V1 features are supported. V1 is the format-version 
baseline.
 | Equality deletes | Supported (read + write). Write via 
`Transaction.WriteEqualityDeletes`; row-level commits via 
`Transaction.NewRowDelta`; delete-only CDC via 
`Transaction.CommitEqualityDeletes` |
 | Partition spec evolution | Supported |
 | Sort order enforcement on write | Supported (PR 
[#1157](https://github.com/apache/iceberg-go/pull/1157), closes 
[#833](https://github.com/apache/iceberg-go/issues/833)) |
-| `ReplaceDataFiles` using `OpReplace` | Pending 
([#841](https://github.com/apache/iceberg-go/issues/841)) |
+| `ReplaceDataFilesByPath` using `OpReplace` | Pending 
([#841](https://github.com/apache/iceberg-go/issues/841)) |
 
 ### V3
 
diff --git a/website/src/releases.md b/website/src/releases.md
index 61ae67689..074e1453f 100644
--- a/website/src/releases.md
+++ b/website/src/releases.md
@@ -59,6 +59,8 @@ Per-release notes (highlights, breaking changes, 
contributors) are published on
     - Option constructors: `WithCleanupLocation`, `WithCleanupFilesOlderThan`, 
`WithCleanupDryRun`, `WithCleanupDeleteFunc`, `WithCleanupMaxConcurrency`, 
`WithPrefixMismatchMode`, `WithEqualSchemes`, `WithEqualAuthorities`. The four 
generic names (`WithLocation`, `WithFilesOlderThan`, `WithDryRun`, 
`WithDeleteFunc`) gained the `WithCleanup` prefix for consistency.
 
     Relatedly, the previously unexported `isGCEnabled` is now 
`table.IsGCEnabled`, so the new package can gate destructive operations on the 
`gc.enabled` table property.
+- **Data-file replacement methods renamed.** Use `ReplaceDataFilesByPath` for 
string paths. Use `ReplaceDataFiles` for prebuilt `DataFile` values instead of 
`ReplaceDataFilesWithDataFiles`.
+
 - `maintenance.PurgeFiles` (previously `Table.PurgeFiles`) now calls 
`IO.Remove` concurrently, with up to 32 calls in flight, when the filesystem 
does not implement `BulkRemovableIO`. Custom IO implementations, including 
those registered with `io.Register`, must make `Remove` safe for concurrent use 
and synchronize any shared mutable state. The bulk deletion path is unchanged.
 
 - **Partition and sort source accessors renamed.** Replace 
`PartitionField.SourceID()` and `SortField.SourceID()` with `FirstSourceID()`. 
Their behavior and serialized fields are unchanged.

Reply via email to