Repository: apache/iceberg-go
Pull request #277 (2025-01-28 20:34:13)

Add CheckTableExists method for rest.go
Similar to the `CheckNamespaceExists` method, I add a new method called `CheckTableExists` and add some unit tests


Patch:
diff --git a/README.md b/README.md
index 4a7948f..ea26dd1 100644
--- a/README.md
+++ b/README.md
@@ -70,7 +70,8 @@ $ cd iceberg-go/cmd/iceberg && go build .
 | Rename Table             |  X   |      |          |  X   |
 | Drop Table               |  X   |      |          |  X   |
 | Alter Table              |      |      |          |      |
-| Set Table Properties     |      |      |          |      |
+| Check Table Exists       |  X   |      |          |      |
+| Set Table Properties     |  X   |      |          |  X   |
 | Create Namespace         |  X   |      |          |  X   |
 | Check Namespace Exists   |  X   |      |          |      |
 | Drop Namespace           |  X   |      |          |  X   |
diff --git a/catalog/rest/rest.go b/catalog/rest/rest.go
index 179f238..a84c395 100644
--- a/catalog/rest/rest.go
+++ b/catalog/rest/rest.go
@@ -973,3 +973,19 @@ func (r *Catalog) CheckNamespaceExists(ctx context.Context, namespace table.Iden
 
 	return true, nil
 }
+
+func (r *Catalog) CheckTableExists(ctx context.Context, identifier table.Identifier) (bool, error) {
+	ns, tbl, err := splitIdentForPath(identifier)
+	if err != nil {
+		return false, err
+	}
+	err = doHead(ctx, r.baseURI, []string{"namespaces", ns, "tables", tbl},
+		r.cl, map[int]error{http.StatusNotFound: catalog.ErrNoSuchTable})
+	if err != nil {
+		if errors.Is(err, catalog.ErrNoSuchTable) {
+			return false, nil
+		}
+		return false, err
+	}
+	return true, nil
+}


Test patch:
diff --git a/catalog/rest/rest_test.go b/catalog/rest/rest_test.go
index 840b03f..2210ae1 100644
--- a/catalog/rest/rest_test.go
+++ b/catalog/rest/rest_test.go
@@ -844,6 +844,49 @@ func (r *RestCatalogSuite) TestCreateTable409() {
 	r.ErrorIs(err, catalog.ErrTableAlreadyExists)
 }
 
+func (r *RestCatalogSuite) TestCheckTableExists204() {
+	r.mux.HandleFunc("/v1/namespaces/fokko/tables/fokko2", func(w http.ResponseWriter, req *http.Request) {
+		r.Require().Equal(http.MethodHead, req.Method)
+
+		for k, v := range TestHeaders {
+			r.Equal(v, req.Header.Values(k))
+		}
+		w.WriteHeader(http.StatusNoContent)
+	})
+
+	cat, err := rest.NewCatalog("rest", r.srv.URL, rest.WithOAuthToken(TestToken))
+	r.Require().NoError(err)
+
+	exists, err := cat.CheckTableExists(context.Background(), catalog.ToIdentifier("fokko", "fokko2"))
+	r.Require().NoError(err)
+	r.True(exists)
+}
+
+func (r *RestCatalogSuite) TestCheckTableExists404() {
+	r.mux.HandleFunc("/v1/namespaces/fokko/tables/nonexistent", func(w http.ResponseWriter, req *http.Request) {
+		r.Require().Equal(http.MethodHead, req.Method)
+
+		for k, v := range TestHeaders {
+			r.Equal(v, req.Header.Values(k))
+		}
+
+		w.WriteHeader(http.StatusNotFound)
+		json.NewEncoder(w).Encode(map[string]any{
+			"error": map[string]any{
+				"message": "Table not found",
+				"type":    "NoSuchTableException",
+				"code":    http.StatusNotFound,
+			},
+		})
+	})
+	cat, err := rest.NewCatalog("rest", r.srv.URL, rest.WithOAuthToken(TestToken))
+	r.Require().NoError(err)
+
+	exists, err := cat.CheckTableExists(context.Background(), catalog.ToIdentifier("fokko", "nonexistent"))
+	r.Require().NoError(err)
+	r.False(exists)
+}
+
 func (r *RestCatalogSuite) TestLoadTable200() {
 	r.mux.HandleFunc("/v1/namespaces/fokko/tables/table", func(w http.ResponseWriter, req *http.Request) {
 		r.Require().Equal(http.MethodGet, req.Method)