Revanth14 commented on code in PR #1324:
URL: https://github.com/apache/iceberg-go/pull/1324#discussion_r3496544329


##########
catalog/rest/scan_planning.go:
##########
@@ -80,29 +88,97 @@ func (r *Catalog) PlanFiles(ctx context.Context, req 
table.ScanPlanningRequest)
 // --- Low-level client methods -----------------------------------------------
 
 // PlanTableScan submits a scan plan. The result is either completed inline,
-// submitted (returns a plan-id to poll), or failed.
+// submitted (returns a plan-id to poll), or failed. A failed planning response
+// decodes as (resp, nil); callers must branch on resp.Status.
 func (r *Catalog) PlanTableScan(ctx context.Context, ident table.Identifier, 
req PlanTableScanRequest) (PlanTableScanResponse, error) {
-       return PlanTableScanResponse{}, fmt.Errorf("%w: plan table scan", 
iceberg.ErrNotImplemented)
+       if err := r.endpoints.check(endpointPlanTableScan); err != nil {
+               return PlanTableScanResponse{}, err
+       }
+
+       path, err := r.scanPlanningPath(endpointPlanTableScan, ident)
+       if err != nil {
+               return PlanTableScanResponse{}, err
+       }
+
+       headers, err := scanPlanningHeaders(req.IdempotencyKey, 
req.AccessDelegation, true)
+       if err != nil {
+               return PlanTableScanResponse{}, err
+       }
+
+       return doPost[PlanTableScanRequest, PlanTableScanResponse](
+               ctx, r.baseURI, path, req, r.cl,
+               map[int]error{http.StatusNotFound: catalog.ErrNoSuchTable}, 
withHeaders(headers))
 }
 
 // FetchPlanningResult polls a previously submitted plan. opts.AccessDelegation
 // is sent as the X-Iceberg-Access-Delegation header so an async poll can still
 // receive plan-scoped storage credentials: the spec defines data-access on 
this
 // endpoint, and the completed-async result is where those credentials are 
vended.
 func (r *Catalog) FetchPlanningResult(ctx context.Context, ident 
table.Identifier, planID string, opts FetchPlanningResultOptions) 
(FetchPlanningResultResponse, error) {
-       return FetchPlanningResultResponse{}, fmt.Errorf("%w: fetch planning 
result", iceberg.ErrNotImplemented)
+       if err := r.endpoints.check(endpointFetchPlanResult); err != nil {
+               return FetchPlanningResultResponse{}, err
+       }
+
+       path, err := r.scanPlanningPath(endpointFetchPlanResult, ident, planID)
+       if err != nil {
+               return FetchPlanningResultResponse{}, err
+       }
+
+       headers, err := scanPlanningHeaders(nil, opts.AccessDelegation, false)
+       if err != nil {
+               return FetchPlanningResultResponse{}, err
+       }
+
+       return doGet[FetchPlanningResultResponse](
+               ctx, r.baseURI, path, r.cl,
+               map[int]error{http.StatusNotFound: ErrPlanExpired}, 
withHeaders(headers))

Review Comment:
   I’m deferring the granular `error.type` split out of this PR.
   
   For the low-level client methods, `FetchPlanningResult` keeps the existing 
status-based 404 mapping to `ErrPlanExpired`, and the comment now calls out 
that finer plan/table/namespace classification should land with the polling 
layer that consumes the retry-vs-abort contract.
   
   I’ll handle that in the `WaitForPlan` follow-up, where we can pin the exact 
`error.type` strings against the spec/OpenAPI and test the retry behavior 
directly.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to