From 01bcbd8db16751858db221b39262503e7b18cc1f Mon Sep 17 00:00:00 2001 From: "databricks-ci-ghec-1[bot]" <184311507+databricks-ci-ghec-1[bot]@users.noreply.github.com> Date: Wed, 2 Sep 2026 12:23:09 +0000 Subject: [PATCH] Release sdk-go --- README.md | 2 +- accessmanagement/CHANGELOG.md | 2 + accessmanagement/go.mod | 14 +- accessmanagement/internal/version.go | 2 +- accessmanagement/v1/client.go | 134 +- accessmanagement/v1/genhelper.go | 20 +- accessmanagement/v1/wire.go | 88 +- aigateway/CHANGELOG.md | 2 + aigateway/go.mod | 14 +- aigateway/internal/version.go | 2 +- aigateway/v1/client.go | 153 +- aigateway/v1/genhelper.go | 20 +- aigateway/v1/model.go | 517 +++--- aigateway/v1/wire.go | 151 +- alerts/CHANGELOG.md | 2 + alerts/go.mod | 14 +- alerts/internal/version.go | 2 +- alerts/v1/client.go | 49 +- alerts/v1/genhelper.go | 20 +- alerts/v2/client.go | 51 +- alerts/v2/genhelper.go | 20 +- alerts/v2/model.go | 43 +- apps/CHANGELOG.md | 2 + apps/go.mod | 14 +- apps/internal/version.go | 2 +- apps/v1/client.go | 354 ++-- apps/v1/genhelper.go | 20 +- apps/v1/model.go | 4 + apps/v1/wire.go | 96 +- auth/CHANGELOG.md | 2 + auth/credentials/default.go | 95 +- auth/credentials/default_test.go | 388 +++- auth/credentials/m2m.go | 10 + auth/credentials/m2m_test.go | 235 ++- auth/go.mod | 2 +- auth/internal/version.go | 2 +- auth/oidc/tokensource.go | 7 + auth/oidc/tokensource_test.go | 239 +++ authentication/CHANGELOG.md | 2 + authentication/go.mod | 14 +- authentication/internal/version.go | 2 +- authentication/v1/client.go | 232 ++- authentication/v1/genhelper.go | 20 +- authentication/v1/wire.go | 144 +- budgetpolicy/CHANGELOG.md | 2 + budgetpolicy/go.mod | 14 +- budgetpolicy/internal/version.go | 2 +- budgetpolicy/v1/client.go | 49 +- budgetpolicy/v1/genhelper.go | 20 +- budgetpolicy/v1/wire.go | 72 +- budgets/CHANGELOG.md | 2 + budgets/go.mod | 14 +- budgets/internal/version.go | 2 +- budgets/v1/client.go | 51 +- budgets/v1/genhelper.go | 20 +- budgets/v1/wire.go | 124 +- cleanrooms/CHANGELOG.md | 2 + cleanrooms/go.mod | 14 +- cleanrooms/internal/version.go | 2 +- cleanrooms/v1/client.go | 371 ++-- cleanrooms/v1/genhelper.go | 20 +- cleanrooms/v1/model.go | 11 +- cleanrooms/v1/wire.go | 264 ++- clusterlibraries/CHANGELOG.md | 2 + clusterlibraries/go.mod | 14 +- clusterlibraries/internal/version.go | 2 +- clusterlibraries/v2/client.go | 14 +- clusterpolicies/CHANGELOG.md | 2 + clusterpolicies/go.mod | 14 +- clusterpolicies/internal/version.go | 2 +- clusterpolicies/v2/client.go | 266 +-- clusterpolicies/v2/genhelper.go | 44 - clusterpolicies/v2/model.go | 88 - clusterpolicies/v2/wire.go | 171 +- clusters/CHANGELOG.md | 2 + clusters/go.mod | 14 +- clusters/internal/version.go | 2 +- clusters/v2/client.go | 468 ++--- clusters/v2/genhelper.go | 44 - clusters/v2/model.go | 84 +- clusters/v2/wire.go | 295 +-- commandexecution/CHANGELOG.md | 2 + commandexecution/go.mod | 14 +- commandexecution/internal/version.go | 2 +- commandexecution/v2/client.go | 88 +- core/CHANGELOG.md | 2 + core/internal/version.go | 2 +- core/profiles/profiles.go | 10 + core/profiles/profiles_test.go | 27 +- core/profiles/testdata/databrickscfg_group_id | 32 + customllms/CHANGELOG.md | 2 + customllms/go.mod | 14 +- customllms/internal/version.go | 2 +- customllms/v1/client.go | 50 +- customllms/v1/genhelper.go | 20 +- database/CHANGELOG.md | 2 + database/go.mod | 14 +- database/internal/version.go | 2 +- database/v1/client.go | 269 ++- database/v1/genhelper.go | 20 +- database/v1/wire.go | 144 +- dataclassification/CHANGELOG.md | 2 + dataclassification/go.mod | 14 +- dataclassification/internal/version.go | 2 +- dataclassification/v1/client.go | 36 +- dataclassification/v1/genhelper.go | 20 +- dataquality/CHANGELOG.md | 2 + dataquality/go.mod | 14 +- dataquality/internal/version.go | 2 +- dataquality/v1/client.go | 198 +- dataquality/v1/genhelper.go | 20 +- dataquality/v1/wire.go | 122 +- disasterrecovery/CHANGELOG.md | 2 + disasterrecovery/go.mod | 14 +- disasterrecovery/internal/version.go | 2 +- disasterrecovery/v1/client.go | 124 +- disasterrecovery/v1/genhelper.go | 20 +- environments/CHANGELOG.md | 2 + environments/go.mod | 14 +- environments/internal/version.go | 2 +- environments/v1/client.go | 109 +- environments/v1/genhelper.go | 20 +- examples/README.md | 51 + examples/authentication/custom/main.go | 58 + examples/authentication/m2m/main.go | 48 + examples/authentication/resolution/main.go | 34 + examples/client_options/main.go | 49 + examples/error_handling/main.go | 43 + examples/field_masks/main.go | 50 + examples/go.mod | 34 + examples/go.sum | 22 + examples/oneofs/main.go | 45 + examples/pagination/main.go | 52 + examples/time_types/main.go | 29 + experiments/CHANGELOG.md | 2 + experiments/go.mod | 14 +- experiments/internal/version.go | 2 +- experiments/v1/client.go | 251 +-- experiments/v1/genhelper.go | 20 +- experiments/v1/wire.go | 286 ++- features/CHANGELOG.md | 2 + features/go.mod | 14 +- features/internal/version.go | 2 +- features/v1/client.go | 506 +++++- features/v1/genhelper.go | 62 +- features/v1/model.go | 548 +++++- features/v1/wire.go | 354 +++- featurestore/CHANGELOG.md | 2 + featurestore/go.mod | 14 +- featurestore/internal/version.go | 2 +- featurestore/v1/client.go | 67 +- featurestore/v1/genhelper.go | 20 +- files/CHANGELOG.md | 2 + files/examples/upload/main.go | 2 +- files/go.mod | 14 +- files/go.sum | 19 + files/internal/version.go | 2 +- files/v2/client.go | 123 +- files/v2/ext_upload_test.go | 7 +- files/v2/genhelper.go | 20 +- files/v2/wire.go | 152 +- forecasting/CHANGELOG.md | 2 + forecasting/go.mod | 14 +- forecasting/internal/version.go | 2 +- forecasting/v1/client.go | 25 +- forecasting/v1/genhelper.go | 20 +- forecasting/v1/wire.go | 96 +- genie/CHANGELOG.md | 2 + genie/go.mod | 14 +- genie/internal/version.go | 2 +- genie/v1/client.go | 620 +++++-- genie/v1/genhelper.go | 20 +- genie/v1/model.go | 23 +- genie/v1/wire.go | 343 +++- gitcredentials/CHANGELOG.md | 2 + gitcredentials/go.mod | 14 +- gitcredentials/internal/version.go | 2 +- gitcredentials/v1/client.go | 38 +- gitcredentials/v1/genhelper.go | 20 +- gitcredentials/v1/wire.go | 188 +- globalinitscripts/CHANGELOG.md | 2 + globalinitscripts/go.mod | 14 +- globalinitscripts/internal/version.go | 2 +- globalinitscripts/v2/client.go | 32 +- globalinitscripts/v2/genhelper.go | 20 +- globalinitscripts/v2/wire.go | 74 +- go.work | 1 + go.work.sum | 28 +- instancepools/CHANGELOG.md | 2 + instancepools/go.mod | 14 +- instancepools/internal/version.go | 2 +- instancepools/v2/client.go | 18 +- instancepools/v2/model.go | 3 + instancepools/v2/wire.go | 3 + instanceprofiles/CHANGELOG.md | 2 + instanceprofiles/go.mod | 14 +- instanceprofiles/internal/version.go | 2 +- instanceprofiles/v2/client.go | 14 +- jobs/CHANGELOG.md | 2 + jobs/go.mod | 14 +- jobs/internal/version.go | 2 +- jobs/v2/client.go | 173 +- jobs/v2/model.go | 78 +- jobs/v2/wire.go | 905 ++++++--- keyconfigurations/CHANGELOG.md | 2 + keyconfigurations/go.mod | 14 +- keyconfigurations/internal/version.go | 2 +- keyconfigurations/v1/client.go | 22 +- keyconfigurations/v1/genhelper.go | 20 +- keyconfigurations/v1/wire.go | 54 +- knowledgeassistants/CHANGELOG.md | 2 + knowledgeassistants/go.mod | 14 +- knowledgeassistants/internal/version.go | 2 +- knowledgeassistants/v1/client.go | 181 +- knowledgeassistants/v1/genhelper.go | 20 +- lakeview/CHANGELOG.md | 2 + lakeview/go.mod | 14 +- lakeview/internal/version.go | 2 +- lakeview/v1/client.go | 300 ++- lakeview/v1/genhelper.go | 20 +- lakeview/v1/wire.go | 74 +- logdelivery/CHANGELOG.md | 2 + logdelivery/go.mod | 14 +- logdelivery/internal/version.go | 2 +- logdelivery/v1/client.go | 41 +- logdelivery/v1/genhelper.go | 20 +- logdelivery/v1/wire.go | 94 +- marketplaces/CHANGELOG.md | 2 + marketplaces/go.mod | 14 +- marketplaces/internal/version.go | 2 +- marketplaces/v1/client.go | 582 +++--- marketplaces/v1/genhelper.go | 20 +- marketplaces/v1/wire.go | 390 +++- modelregistry/CHANGELOG.md | 2 + modelregistry/go.mod | 14 +- modelregistry/internal/version.go | 2 +- modelregistry/v1/client.go | 188 +- modelregistry/v1/wire.go | 220 ++- modelserving/CHANGELOG.md | 2 + modelserving/go.mod | 14 +- modelserving/internal/version.go | 2 +- modelserving/v1/client.go | 196 +- modelserving/v1/genhelper.go | 20 +- modelserving/v1/wire.go | 190 +- modelservingquery/CHANGELOG.md | 2 + modelservingquery/go.mod | 14 +- modelservingquery/internal/version.go | 2 +- modelservingquery/v1/client.go | 10 +- modelservingquery/v1/ext_query_dp.go | 6 +- modelservingquery/v1/ext_query_dp_test.go | 7 +- modelservingquery/v1/genhelper.go | 20 +- modelservingquery/v1/wire.go | 53 +- networking/CHANGELOG.md | 2 + networking/go.mod | 14 +- networking/internal/version.go | 2 +- networking/v1/client.go | 396 ++-- networking/v1/genhelper.go | 20 +- networking/v1/model.go | 38 +- networking/v1/wire.go | 380 +++- notificationdestinations/CHANGELOG.md | 2 + notificationdestinations/go.mod | 14 +- notificationdestinations/internal/version.go | 2 +- notificationdestinations/v1/client.go | 49 +- notificationdestinations/v1/genhelper.go | 20 +- notificationdestinations/v1/wire.go | 56 +- oauth/CHANGELOG.md | 2 + oauth/go.mod | 14 +- oauth/internal/version.go | 2 +- oauth/v1/client.go | 117 +- oauth/v1/genhelper.go | 20 +- oauth/v1/wire.go | 62 +- options/CHANGELOG.md | 2 + options/client/client.go | 30 +- options/client/client_test.go | 20 + options/go.mod | 15 +- options/go.sum | 20 +- options/internal/version.go | 2 +- options/internaloptions/internaloptions.go | 35 +- .../internaloptions/internaloptions_test.go | 177 +- pipelines/CHANGELOG.md | 2 + pipelines/go.mod | 14 +- pipelines/internal/version.go | 2 +- pipelines/v2/client.go | 153 +- pipelines/v2/genhelper.go | 20 +- pipelines/v2/model.go | 42 +- pipelines/v2/wire.go | 226 ++- policyfamilies/CHANGELOG.md | 2 + policyfamilies/go.mod | 14 +- policyfamilies/internal/version.go | 2 +- policyfamilies/v2/client.go | 29 +- policyfamilies/v2/genhelper.go | 20 +- policyfamilies/v2/wire.go | 66 +- postgres/CHANGELOG.md | 2 + postgres/go.mod | 14 +- postgres/internal/version.go | 2 +- postgres/v1/client.go | 1609 +++++++++++++---- postgres/v1/genhelper.go | 20 +- postgres/v1/model.go | 294 ++- postgres/v1/wire.go | 705 +++++++- queries/CHANGELOG.md | 2 + queries/go.mod | 14 +- queries/internal/version.go | 2 +- queries/v1/client.go | 74 +- queries/v1/genhelper.go | 20 +- queryhistory/CHANGELOG.md | 2 + queryhistory/go.mod | 14 +- queryhistory/internal/version.go | 2 +- queryhistory/v1/client.go | 4 +- queryhistory/v1/wire.go | 358 +++- repos/CHANGELOG.md | 2 + repos/go.mod | 14 +- repos/internal/version.go | 2 +- repos/v1/client.go | 49 +- repos/v1/genhelper.go | 20 +- repos/v1/wire.go | 94 +- scim/CHANGELOG.md | 2 + scim/go.mod | 14 +- scim/internal/version.go | 2 +- scim/v1/client.go | 374 ++-- scim/v1/genhelper.go | 20 +- scim/v1/wire.go | 189 +- secrets/CHANGELOG.md | 2 + secrets/go.mod | 14 +- secrets/internal/version.go | 2 +- secrets/v1/client.go | 42 +- secrets/v1/wire.go | 56 +- settings/CHANGELOG.md | 2 + settings/go.mod | 14 +- settings/internal/version.go | 2 +- settings/v2/client.go | 129 +- settings/v2/genhelper.go | 20 +- sharing/CHANGELOG.md | 2 + sharing/go.mod | 14 +- sharing/internal/version.go | 2 +- sharing/v1/client.go | 309 ++-- sharing/v1/genhelper.go | 20 +- sharing/v1/wire.go | 312 +++- statementexecution/CHANGELOG.md | 2 + statementexecution/go.mod | 14 +- statementexecution/internal/version.go | 2 +- statementexecution/v1/client.go | 36 +- statementexecution/v1/genhelper.go | 20 +- statementexecution/v1/wire.go | 155 +- storageconfigurations/CHANGELOG.md | 2 + storageconfigurations/go.mod | 14 +- storageconfigurations/internal/version.go | 2 +- storageconfigurations/v1/client.go | 22 +- storageconfigurations/v1/genhelper.go | 20 +- storageconfigurations/v1/wire.go | 54 +- supervisoragents/CHANGELOG.md | 2 + supervisoragents/go.mod | 14 +- supervisoragents/internal/version.go | 2 +- supervisoragents/v1/client.go | 171 +- supervisoragents/v1/genhelper.go | 20 +- tagassignments/CHANGELOG.md | 2 + tagassignments/go.mod | 14 +- tagassignments/internal/version.go | 2 +- tagassignments/v1/client.go | 97 +- tagassignments/v1/genhelper.go | 20 +- tagpolicies/CHANGELOG.md | 2 + tagpolicies/go.mod | 14 +- tagpolicies/internal/version.go | 2 +- tagpolicies/v1/client.go | 49 +- tagpolicies/v1/genhelper.go | 20 +- tokenmanagement/CHANGELOG.md | 2 + tokenmanagement/go.mod | 14 +- tokenmanagement/internal/version.go | 2 +- tokenmanagement/v1/client.go | 34 +- tokenmanagement/v1/genhelper.go | 20 +- tokenmanagement/v1/wire.go | 156 +- tokens/CHANGELOG.md | 2 + tokens/go.mod | 14 +- tokens/internal/version.go | 2 +- tokens/v1/client.go | 20 +- tokens/v1/genhelper.go | 20 +- tokens/v1/wire.go | 88 +- uc/abacpolicies/CHANGELOG.md | 2 + uc/abacpolicies/go.mod | 14 +- uc/abacpolicies/internal/version.go | 2 +- uc/abacpolicies/v1/client.go | 97 +- uc/abacpolicies/v1/genhelper.go | 20 +- uc/abacpolicies/v1/model.go | 75 +- uc/abacpolicies/v1/wire.go | 273 ++- uc/artifactallowlists/CHANGELOG.md | 2 + uc/artifactallowlists/go.mod | 14 +- uc/artifactallowlists/internal/version.go | 2 +- uc/artifactallowlists/v1/client.go | 13 +- uc/artifactallowlists/v1/genhelper.go | 20 +- uc/artifactallowlists/v1/wire.go | 62 +- uc/catalogs/CHANGELOG.md | 2 + uc/catalogs/go.mod | 14 +- uc/catalogs/internal/version.go | 2 +- uc/catalogs/v1/client.go | 53 +- uc/catalogs/v1/genhelper.go | 20 +- uc/catalogs/v1/model.go | 6 +- uc/catalogs/v1/wire.go | 118 +- uc/connections/CHANGELOG.md | 2 + uc/connections/go.mod | 14 +- uc/connections/internal/version.go | 2 +- uc/connections/v1/client.go | 49 +- uc/connections/v1/genhelper.go | 20 +- uc/connections/v1/model.go | 6 +- uc/connections/v1/wire.go | 94 +- uc/credentials/CHANGELOG.md | 2 + uc/credentials/go.mod | 14 +- uc/credentials/internal/version.go | 2 +- uc/credentials/v1/client.go | 212 ++- uc/credentials/v1/genhelper.go | 20 +- uc/credentials/v1/wire.go | 214 ++- uc/entitytagassignments/CHANGELOG.md | 2 + uc/entitytagassignments/go.mod | 14 +- uc/entitytagassignments/internal/version.go | 2 +- uc/entitytagassignments/v1/client.go | 97 +- uc/entitytagassignments/v1/genhelper.go | 20 +- uc/externallineage/CHANGELOG.md | 2 + uc/externallineage/go.mod | 14 +- uc/externallineage/internal/version.go | 2 +- uc/externallineage/v1/client.go | 31 +- uc/externallineage/v1/wire.go | 54 +- uc/externallocations/CHANGELOG.md | 2 + uc/externallocations/go.mod | 14 +- uc/externallocations/internal/version.go | 2 +- uc/externallocations/v1/client.go | 53 +- uc/externallocations/v1/genhelper.go | 20 +- uc/externallocations/v1/wire.go | 94 +- uc/externalmetadata/CHANGELOG.md | 2 + uc/externalmetadata/go.mod | 14 +- uc/externalmetadata/internal/version.go | 2 +- uc/externalmetadata/v1/client.go | 49 +- uc/externalmetadata/v1/genhelper.go | 20 +- uc/functions/CHANGELOG.md | 2 + uc/functions/go.mod | 14 +- uc/functions/internal/version.go | 2 +- uc/functions/v1/client.go | 53 +- uc/functions/v1/genhelper.go | 20 +- uc/functions/v1/model.go | 9 +- uc/functions/v1/wire.go | 94 +- uc/grants/CHANGELOG.md | 2 + uc/grants/go.mod | 14 +- uc/grants/internal/version.go | 2 +- uc/grants/v1/client.go | 110 +- uc/grants/v1/genhelper.go | 20 +- uc/metastores/CHANGELOG.md | 2 + uc/metastores/go.mod | 14 +- uc/metastores/internal/version.go | 2 +- uc/metastores/v1/client.go | 181 +- uc/metastores/v1/genhelper.go | 20 +- uc/metastores/v1/wire.go | 266 ++- uc/onlinetables/CHANGELOG.md | 2 + uc/onlinetables/go.mod | 14 +- uc/onlinetables/internal/version.go | 2 +- uc/onlinetables/v1/client.go | 33 +- uc/onlinetables/v1/genhelper.go | 20 +- uc/onlinetables/v1/wire.go | 134 +- uc/registeredmodels/CHANGELOG.md | 2 + uc/registeredmodels/go.mod | 14 +- uc/registeredmodels/internal/version.go | 2 +- uc/registeredmodels/v1/client.go | 168 +- uc/registeredmodels/v1/genhelper.go | 20 +- uc/registeredmodels/v1/wire.go | 246 ++- uc/resourcequotas/CHANGELOG.md | 2 + uc/resourcequotas/go.mod | 14 +- uc/resourcequotas/internal/version.go | 2 +- uc/resourcequotas/v1/client.go | 39 +- uc/resourcequotas/v1/genhelper.go | 20 +- uc/resourcequotas/v1/model.go | 6 +- uc/resourcequotas/v1/wire.go | 54 +- uc/rfa/CHANGELOG.md | 2 + uc/rfa/go.mod | 14 +- uc/rfa/internal/version.go | 2 +- uc/rfa/v1/client.go | 28 +- uc/rfa/v1/genhelper.go | 20 +- uc/rfa/v1/model.go | 6 +- uc/schemas/CHANGELOG.md | 2 + uc/schemas/go.mod | 14 +- uc/schemas/internal/version.go | 2 +- uc/schemas/v1/client.go | 53 +- uc/schemas/v1/genhelper.go | 20 +- uc/schemas/v1/wire.go | 118 +- uc/secrets/CHANGELOG.md | 2 + uc/secrets/go.mod | 14 +- uc/secrets/internal/version.go | 2 +- uc/secrets/v1/client.go | 51 +- uc/secrets/v1/genhelper.go | 20 +- uc/systemschemas/CHANGELOG.md | 2 + uc/systemschemas/go.mod | 14 +- uc/systemschemas/internal/version.go | 2 +- uc/systemschemas/v1/client.go | 55 +- uc/systemschemas/v1/genhelper.go | 20 +- uc/tables/CHANGELOG.md | 2 + uc/tables/go.mod | 14 +- uc/tables/internal/version.go | 2 +- uc/tables/v1/client.go | 92 +- uc/tables/v1/genhelper.go | 20 +- uc/tables/v1/model.go | 20 +- uc/tables/v1/wire.go | 118 +- uc/volumes/CHANGELOG.md | 2 + uc/volumes/go.mod | 14 +- uc/volumes/internal/version.go | 2 +- uc/volumes/v1/client.go | 51 +- uc/volumes/v1/genhelper.go | 20 +- uc/volumes/v1/wire.go | 94 +- uc/workspacebindings/CHANGELOG.md | 2 + uc/workspacebindings/go.mod | 14 +- uc/workspacebindings/internal/version.go | 2 +- uc/workspacebindings/v1/client.go | 65 +- uc/workspacebindings/v1/genhelper.go | 20 +- uc/workspacebindings/v1/wire.go | 94 +- usagedashboards/CHANGELOG.md | 2 + usagedashboards/go.mod | 14 +- usagedashboards/internal/version.go | 2 +- usagedashboards/v1/client.go | 8 +- usagedashboards/v1/genhelper.go | 20 +- usagedashboards/v1/wire.go | 66 +- vectorsearch/CHANGELOG.md | 2 + vectorsearch/go.mod | 14 +- vectorsearch/internal/version.go | 2 +- vectorsearch/v1/client.go | 193 +- vectorsearch/v1/genhelper.go | 20 +- vectorsearch/v1/wire.go | 121 +- warehouses/CHANGELOG.md | 2 + warehouses/go.mod | 14 +- warehouses/internal/version.go | 2 +- warehouses/v1/client.go | 176 +- warehouses/v1/genhelper.go | 20 +- warehouses/v1/wire.go | 74 +- workspaces/CHANGELOG.md | 2 + workspaces/go.mod | 14 +- workspaces/internal/version.go | 2 +- workspaces/v1/client.go | 58 +- workspaces/v1/genhelper.go | 20 +- workspaces/v1/wire.go | 74 +- 532 files changed, 21629 insertions(+), 8147 deletions(-) mode change 100755 => 100644 accessmanagement/v1/client.go mode change 100755 => 100644 accessmanagement/v1/genhelper.go mode change 100755 => 100644 accessmanagement/v1/wire.go mode change 100755 => 100644 aigateway/v1/client.go mode change 100755 => 100644 aigateway/v1/genhelper.go mode change 100755 => 100644 aigateway/v1/model.go mode change 100755 => 100644 aigateway/v1/wire.go mode change 100755 => 100644 alerts/v1/client.go mode change 100755 => 100644 alerts/v1/genhelper.go mode change 100755 => 100644 alerts/v2/client.go mode change 100755 => 100644 alerts/v2/genhelper.go mode change 100755 => 100644 alerts/v2/model.go mode change 100755 => 100644 apps/v1/client.go mode change 100755 => 100644 apps/v1/genhelper.go mode change 100755 => 100644 apps/v1/model.go mode change 100755 => 100644 apps/v1/wire.go mode change 100755 => 100644 authentication/v1/client.go mode change 100755 => 100644 authentication/v1/genhelper.go mode change 100755 => 100644 authentication/v1/wire.go mode change 100755 => 100644 budgetpolicy/v1/client.go mode change 100755 => 100644 budgetpolicy/v1/genhelper.go mode change 100755 => 100644 budgetpolicy/v1/wire.go mode change 100755 => 100644 budgets/v1/client.go mode change 100755 => 100644 budgets/v1/genhelper.go mode change 100755 => 100644 budgets/v1/wire.go mode change 100755 => 100644 cleanrooms/v1/client.go mode change 100755 => 100644 cleanrooms/v1/genhelper.go mode change 100755 => 100644 cleanrooms/v1/model.go mode change 100755 => 100644 cleanrooms/v1/wire.go mode change 100755 => 100644 clusterlibraries/v2/client.go mode change 100755 => 100644 clusterpolicies/v2/client.go mode change 100755 => 100644 clusterpolicies/v2/genhelper.go mode change 100755 => 100644 clusterpolicies/v2/model.go mode change 100755 => 100644 clusterpolicies/v2/wire.go mode change 100755 => 100644 clusters/v2/client.go mode change 100755 => 100644 clusters/v2/genhelper.go mode change 100755 => 100644 clusters/v2/model.go mode change 100755 => 100644 clusters/v2/wire.go mode change 100755 => 100644 commandexecution/v2/client.go create mode 100644 core/profiles/testdata/databrickscfg_group_id mode change 100755 => 100644 customllms/v1/client.go mode change 100755 => 100644 customllms/v1/genhelper.go mode change 100755 => 100644 database/v1/client.go mode change 100755 => 100644 database/v1/genhelper.go mode change 100755 => 100644 database/v1/wire.go mode change 100755 => 100644 dataclassification/v1/client.go mode change 100755 => 100644 dataclassification/v1/genhelper.go mode change 100755 => 100644 dataquality/v1/client.go mode change 100755 => 100644 dataquality/v1/genhelper.go mode change 100755 => 100644 dataquality/v1/wire.go mode change 100755 => 100644 disasterrecovery/v1/client.go mode change 100755 => 100644 disasterrecovery/v1/genhelper.go mode change 100755 => 100644 environments/v1/client.go mode change 100755 => 100644 environments/v1/genhelper.go create mode 100644 examples/README.md create mode 100644 examples/authentication/custom/main.go create mode 100644 examples/authentication/m2m/main.go create mode 100644 examples/authentication/resolution/main.go create mode 100644 examples/client_options/main.go create mode 100644 examples/error_handling/main.go create mode 100644 examples/field_masks/main.go create mode 100644 examples/go.mod create mode 100644 examples/go.sum create mode 100644 examples/oneofs/main.go create mode 100644 examples/pagination/main.go create mode 100644 examples/time_types/main.go mode change 100755 => 100644 experiments/v1/client.go mode change 100755 => 100644 experiments/v1/genhelper.go mode change 100755 => 100644 experiments/v1/wire.go mode change 100755 => 100644 features/v1/client.go mode change 100755 => 100644 features/v1/genhelper.go mode change 100755 => 100644 features/v1/model.go mode change 100755 => 100644 features/v1/wire.go mode change 100755 => 100644 featurestore/v1/client.go mode change 100755 => 100644 featurestore/v1/genhelper.go mode change 100755 => 100644 files/v2/client.go mode change 100755 => 100644 files/v2/genhelper.go mode change 100755 => 100644 files/v2/wire.go mode change 100755 => 100644 forecasting/v1/client.go mode change 100755 => 100644 forecasting/v1/genhelper.go mode change 100755 => 100644 forecasting/v1/wire.go mode change 100755 => 100644 genie/v1/client.go mode change 100755 => 100644 genie/v1/genhelper.go mode change 100755 => 100644 genie/v1/model.go mode change 100755 => 100644 genie/v1/wire.go mode change 100755 => 100644 gitcredentials/v1/client.go mode change 100755 => 100644 gitcredentials/v1/genhelper.go mode change 100755 => 100644 gitcredentials/v1/wire.go mode change 100755 => 100644 globalinitscripts/v2/client.go mode change 100755 => 100644 globalinitscripts/v2/genhelper.go mode change 100755 => 100644 globalinitscripts/v2/wire.go mode change 100755 => 100644 instancepools/v2/client.go mode change 100755 => 100644 instancepools/v2/model.go mode change 100755 => 100644 instancepools/v2/wire.go mode change 100755 => 100644 instanceprofiles/v2/client.go mode change 100755 => 100644 jobs/v2/client.go mode change 100755 => 100644 jobs/v2/model.go mode change 100755 => 100644 jobs/v2/wire.go mode change 100755 => 100644 keyconfigurations/v1/client.go mode change 100755 => 100644 keyconfigurations/v1/genhelper.go mode change 100755 => 100644 keyconfigurations/v1/wire.go mode change 100755 => 100644 knowledgeassistants/v1/client.go mode change 100755 => 100644 knowledgeassistants/v1/genhelper.go mode change 100755 => 100644 lakeview/v1/client.go mode change 100755 => 100644 lakeview/v1/genhelper.go mode change 100755 => 100644 lakeview/v1/wire.go mode change 100755 => 100644 logdelivery/v1/client.go mode change 100755 => 100644 logdelivery/v1/genhelper.go mode change 100755 => 100644 logdelivery/v1/wire.go mode change 100755 => 100644 marketplaces/v1/client.go mode change 100755 => 100644 marketplaces/v1/genhelper.go mode change 100755 => 100644 marketplaces/v1/wire.go mode change 100755 => 100644 modelregistry/v1/client.go mode change 100755 => 100644 modelregistry/v1/wire.go mode change 100755 => 100644 modelserving/v1/client.go mode change 100755 => 100644 modelserving/v1/genhelper.go mode change 100755 => 100644 modelserving/v1/wire.go mode change 100755 => 100644 modelservingquery/v1/client.go mode change 100755 => 100644 modelservingquery/v1/genhelper.go mode change 100755 => 100644 modelservingquery/v1/wire.go mode change 100755 => 100644 networking/v1/client.go mode change 100755 => 100644 networking/v1/genhelper.go mode change 100755 => 100644 networking/v1/model.go mode change 100755 => 100644 networking/v1/wire.go mode change 100755 => 100644 notificationdestinations/v1/client.go mode change 100755 => 100644 notificationdestinations/v1/genhelper.go mode change 100755 => 100644 notificationdestinations/v1/wire.go mode change 100755 => 100644 oauth/v1/client.go mode change 100755 => 100644 oauth/v1/genhelper.go mode change 100755 => 100644 oauth/v1/wire.go mode change 100755 => 100644 pipelines/v2/client.go mode change 100755 => 100644 pipelines/v2/genhelper.go mode change 100755 => 100644 pipelines/v2/model.go mode change 100755 => 100644 pipelines/v2/wire.go mode change 100755 => 100644 policyfamilies/v2/client.go mode change 100755 => 100644 policyfamilies/v2/genhelper.go mode change 100755 => 100644 policyfamilies/v2/wire.go mode change 100755 => 100644 postgres/v1/client.go mode change 100755 => 100644 postgres/v1/genhelper.go mode change 100755 => 100644 postgres/v1/model.go mode change 100755 => 100644 postgres/v1/wire.go mode change 100755 => 100644 queries/v1/client.go mode change 100755 => 100644 queries/v1/genhelper.go mode change 100755 => 100644 queryhistory/v1/client.go mode change 100755 => 100644 queryhistory/v1/wire.go mode change 100755 => 100644 repos/v1/client.go mode change 100755 => 100644 repos/v1/genhelper.go mode change 100755 => 100644 repos/v1/wire.go mode change 100755 => 100644 scim/v1/client.go mode change 100755 => 100644 scim/v1/genhelper.go mode change 100755 => 100644 scim/v1/wire.go mode change 100755 => 100644 secrets/v1/client.go mode change 100755 => 100644 secrets/v1/wire.go mode change 100755 => 100644 settings/v2/client.go mode change 100755 => 100644 settings/v2/genhelper.go mode change 100755 => 100644 sharing/v1/client.go mode change 100755 => 100644 sharing/v1/genhelper.go mode change 100755 => 100644 sharing/v1/wire.go mode change 100755 => 100644 statementexecution/v1/client.go mode change 100755 => 100644 statementexecution/v1/genhelper.go mode change 100755 => 100644 statementexecution/v1/wire.go mode change 100755 => 100644 storageconfigurations/v1/client.go mode change 100755 => 100644 storageconfigurations/v1/genhelper.go mode change 100755 => 100644 storageconfigurations/v1/wire.go mode change 100755 => 100644 supervisoragents/v1/client.go mode change 100755 => 100644 supervisoragents/v1/genhelper.go mode change 100755 => 100644 tagassignments/v1/client.go mode change 100755 => 100644 tagassignments/v1/genhelper.go mode change 100755 => 100644 tagpolicies/v1/client.go mode change 100755 => 100644 tagpolicies/v1/genhelper.go mode change 100755 => 100644 tokenmanagement/v1/client.go mode change 100755 => 100644 tokenmanagement/v1/genhelper.go mode change 100755 => 100644 tokenmanagement/v1/wire.go mode change 100755 => 100644 tokens/v1/client.go mode change 100755 => 100644 tokens/v1/genhelper.go mode change 100755 => 100644 tokens/v1/wire.go mode change 100755 => 100644 uc/abacpolicies/v1/client.go mode change 100755 => 100644 uc/abacpolicies/v1/genhelper.go mode change 100755 => 100644 uc/abacpolicies/v1/model.go mode change 100755 => 100644 uc/abacpolicies/v1/wire.go mode change 100755 => 100644 uc/artifactallowlists/v1/client.go mode change 100755 => 100644 uc/artifactallowlists/v1/genhelper.go mode change 100755 => 100644 uc/artifactallowlists/v1/wire.go mode change 100755 => 100644 uc/catalogs/v1/client.go mode change 100755 => 100644 uc/catalogs/v1/genhelper.go mode change 100755 => 100644 uc/catalogs/v1/model.go mode change 100755 => 100644 uc/catalogs/v1/wire.go mode change 100755 => 100644 uc/connections/v1/client.go mode change 100755 => 100644 uc/connections/v1/genhelper.go mode change 100755 => 100644 uc/connections/v1/model.go mode change 100755 => 100644 uc/connections/v1/wire.go mode change 100755 => 100644 uc/credentials/v1/client.go mode change 100755 => 100644 uc/credentials/v1/genhelper.go mode change 100755 => 100644 uc/credentials/v1/wire.go mode change 100755 => 100644 uc/entitytagassignments/v1/client.go mode change 100755 => 100644 uc/entitytagassignments/v1/genhelper.go mode change 100755 => 100644 uc/externallineage/v1/client.go mode change 100755 => 100644 uc/externallineage/v1/wire.go mode change 100755 => 100644 uc/externallocations/v1/client.go mode change 100755 => 100644 uc/externallocations/v1/genhelper.go mode change 100755 => 100644 uc/externallocations/v1/wire.go mode change 100755 => 100644 uc/externalmetadata/v1/client.go mode change 100755 => 100644 uc/externalmetadata/v1/genhelper.go mode change 100755 => 100644 uc/functions/v1/client.go mode change 100755 => 100644 uc/functions/v1/genhelper.go mode change 100755 => 100644 uc/functions/v1/model.go mode change 100755 => 100644 uc/functions/v1/wire.go mode change 100755 => 100644 uc/grants/v1/client.go mode change 100755 => 100644 uc/grants/v1/genhelper.go mode change 100755 => 100644 uc/metastores/v1/client.go mode change 100755 => 100644 uc/metastores/v1/genhelper.go mode change 100755 => 100644 uc/metastores/v1/wire.go mode change 100755 => 100644 uc/onlinetables/v1/client.go mode change 100755 => 100644 uc/onlinetables/v1/genhelper.go mode change 100755 => 100644 uc/onlinetables/v1/wire.go mode change 100755 => 100644 uc/registeredmodels/v1/client.go mode change 100755 => 100644 uc/registeredmodels/v1/genhelper.go mode change 100755 => 100644 uc/registeredmodels/v1/wire.go mode change 100755 => 100644 uc/resourcequotas/v1/client.go mode change 100755 => 100644 uc/resourcequotas/v1/genhelper.go mode change 100755 => 100644 uc/resourcequotas/v1/model.go mode change 100755 => 100644 uc/resourcequotas/v1/wire.go mode change 100755 => 100644 uc/rfa/v1/client.go mode change 100755 => 100644 uc/rfa/v1/genhelper.go mode change 100755 => 100644 uc/rfa/v1/model.go mode change 100755 => 100644 uc/schemas/v1/client.go mode change 100755 => 100644 uc/schemas/v1/genhelper.go mode change 100755 => 100644 uc/schemas/v1/wire.go mode change 100755 => 100644 uc/secrets/v1/client.go mode change 100755 => 100644 uc/secrets/v1/genhelper.go mode change 100755 => 100644 uc/systemschemas/v1/client.go mode change 100755 => 100644 uc/systemschemas/v1/genhelper.go mode change 100755 => 100644 uc/tables/v1/client.go mode change 100755 => 100644 uc/tables/v1/genhelper.go mode change 100755 => 100644 uc/tables/v1/model.go mode change 100755 => 100644 uc/tables/v1/wire.go mode change 100755 => 100644 uc/volumes/v1/client.go mode change 100755 => 100644 uc/volumes/v1/genhelper.go mode change 100755 => 100644 uc/volumes/v1/wire.go mode change 100755 => 100644 uc/workspacebindings/v1/client.go mode change 100755 => 100644 uc/workspacebindings/v1/genhelper.go mode change 100755 => 100644 uc/workspacebindings/v1/wire.go mode change 100755 => 100644 usagedashboards/v1/client.go mode change 100755 => 100644 usagedashboards/v1/genhelper.go mode change 100755 => 100644 usagedashboards/v1/wire.go mode change 100755 => 100644 vectorsearch/v1/client.go mode change 100755 => 100644 vectorsearch/v1/genhelper.go mode change 100755 => 100644 vectorsearch/v1/wire.go mode change 100755 => 100644 warehouses/v1/client.go mode change 100755 => 100644 warehouses/v1/genhelper.go mode change 100755 => 100644 warehouses/v1/wire.go mode change 100755 => 100644 workspaces/v1/client.go mode change 100755 => 100644 workspaces/v1/genhelper.go mode change 100755 => 100644 workspaces/v1/wire.go diff --git a/README.md b/README.md index 3b3e331..d4684ca 100644 --- a/README.md +++ b/README.md @@ -9,4 +9,4 @@ > - ⚠️ **Breaking changes may occur at any time** > - 🔬 **APIs are experimental and unstable** > -> For production use cases, please wait for the stable release or use the current [Databricks SDK](https://github.com/databricks/databricks-sdk-go). +> For production use cases, please wait for the stable release or use the current [Databricks SDK](https://github.com/databricks/databricks-sdk-go). diff --git a/accessmanagement/CHANGELOG.md b/accessmanagement/CHANGELOG.md index 6224c04..19f237c 100644 --- a/accessmanagement/CHANGELOG.md +++ b/accessmanagement/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/accessmanagement/go.mod b/accessmanagement/go.mod index 18e8727..1088410 100644 --- a/accessmanagement/go.mod +++ b/accessmanagement/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/accessmanagement/internal/version.go b/accessmanagement/internal/version.go index 621844f..9b73f49 100644 --- a/accessmanagement/internal/version.go +++ b/accessmanagement/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-accessmanagement" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/accessmanagement/v1/client.go b/accessmanagement/v1/client.go old mode 100755 new mode 100644 index 6165da2..c797301 --- a/accessmanagement/v1/client.go +++ b/accessmanagement/v1/client.go @@ -76,7 +76,7 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Deletes the workspace permissions assignment in a given account and workspace // for the specified principal. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteWorkspacePermissionAssignment(ctx context.Context, req *DeleteWorkspacePermissionAssignmentRequest, opts ...call.Option) (*DeleteWorkspacePermissionAssignmentResponse, error) { +func (c *internalClient) DeleteWorkspacePermissionAssignment(ctx context.Context, req DeleteWorkspacePermissionAssignmentRequest, opts ...call.Option) (*DeleteWorkspacePermissionAssignmentResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -93,9 +93,17 @@ func (c *internalClient) DeleteWorkspacePermissionAssignment(ctx context.Context pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/workspaces/") - pb.singleSegment(*req.WorkspaceId) + if req.WorkspaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.WorkspaceId) + } pb.literal("/permissionassignments/principals/") - pb.singleSegment(*req.PrincipalId) + if req.PrincipalId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PrincipalId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -136,7 +144,7 @@ func (c *internalClient) DeleteWorkspacePermissionAssignment(ctx context.Context // Get the permission assignments for the specified and . // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListWorkspacePermissionAssignments(ctx context.Context, req *ListWorkspacePermissionAssignmentsRequest, opts ...call.Option) (*ListWorkspacePermissionAssignmentsResponse, error) { +func (c *internalClient) ListWorkspacePermissionAssignments(ctx context.Context, req ListWorkspacePermissionAssignmentsRequest, opts ...call.Option) (*ListWorkspacePermissionAssignmentsResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -153,7 +161,11 @@ func (c *internalClient) ListWorkspacePermissionAssignments(ctx context.Context, pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/workspaces/") - pb.singleSegment(*req.WorkspaceId) + if req.WorkspaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.WorkspaceId) + } pb.literal("/permissionassignments") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -202,7 +214,7 @@ func (c *internalClient) ListWorkspacePermissionAssignments(ctx context.Context, // Get an array of workspace permissions for the specified account and // workspace. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListWorkspacePermissions(ctx context.Context, req *ListWorkspacePermissionsRequest, opts ...call.Option) (*ListWorkspacePermissionsResponse, error) { +func (c *internalClient) ListWorkspacePermissions(ctx context.Context, req ListWorkspacePermissionsRequest, opts ...call.Option) (*ListWorkspacePermissionsResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -219,7 +231,11 @@ func (c *internalClient) ListWorkspacePermissions(ctx context.Context, req *List pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/workspaces/") - pb.singleSegment(*req.WorkspaceId) + if req.WorkspaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.WorkspaceId) + } pb.literal("/permissionassignments/permissions") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -268,8 +284,8 @@ func (c *internalClient) ListWorkspacePermissions(ctx context.Context, req *List // Creates or updates the workspace permissions assignment in a given account // and workspace for the specified principal. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdateWorkspacePermissionAssignment(ctx context.Context, req *UpdateWorkspacePermissionAssignmentRequest, opts ...call.Option) (*WorkspacePermissionAssignmentOutput, error) { - wireReq, err := updateWorkspacePermissionAssignmentRequestToWire(req) +func (c *internalClient) UpdateWorkspacePermissionAssignment(ctx context.Context, req UpdateWorkspacePermissionAssignmentRequest, opts ...call.Option) (*WorkspacePermissionAssignmentOutput, error) { + wireReq, err := updateWorkspacePermissionAssignmentRequestToWire(&req) if err != nil { return nil, err } @@ -293,9 +309,17 @@ func (c *internalClient) UpdateWorkspacePermissionAssignment(ctx context.Context pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/workspaces/") - pb.singleSegment(*req.WorkspaceId) + if req.WorkspaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.WorkspaceId) + } pb.literal("/permissionassignments/principals/") - pb.singleSegment(*req.PrincipalId) + if req.PrincipalId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PrincipalId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -345,8 +369,8 @@ func (c *internalClient) UpdateWorkspacePermissionAssignment(ctx context.Context // contains a list of access rules on the said resource. Currently only a // default rule set for each resource is supported. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetRuleSet(ctx context.Context, req *GetRuleSetRequest, opts ...call.Option) (*RuleSet, error) { - wireReq, err := getRuleSetRequestToWire(req) +func (c *internalClient) GetRuleSet(ctx context.Context, req GetRuleSetRequest, opts ...call.Option) (*RuleSet, error) { + wireReq, err := getRuleSetRequestToWire(&req) if err != nil { return nil, err } @@ -419,8 +443,8 @@ func (c *internalClient) GetRuleSet(ctx context.Context, req *GetRuleSetRequest, // Get a rule set by its name. A rule set is always attached to a resource and // contains a list of access rules on the said resource. Currently only a // default rule set for each resource is supported. -func (c *internalClient) GetRuleSetProxy(ctx context.Context, req *GetRuleSetRequest, opts ...call.Option) (*RuleSet, error) { - wireReq, err := getRuleSetRequestToWire(req) +func (c *internalClient) GetRuleSetProxy(ctx context.Context, req GetRuleSetRequest, opts ...call.Option) (*RuleSet, error) { + wireReq, err := getRuleSetRequestToWire(&req) if err != nil { return nil, err } @@ -492,8 +516,8 @@ func (c *internalClient) GetRuleSetProxy(ctx context.Context, req *GetRuleSetReq // is grantable if the rule set on the resource can contain an access rule of // the role. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListAssignableRolesForResource(ctx context.Context, req *ListAssignableRolesForResourceRequest, opts ...call.Option) (*ListAssignableRolesForResourceResponse, error) { - wireReq, err := listAssignableRolesForResourceRequestToWire(req) +func (c *internalClient) ListAssignableRolesForResource(ctx context.Context, req ListAssignableRolesForResourceRequest, opts ...call.Option) (*ListAssignableRolesForResourceResponse, error) { + wireReq, err := listAssignableRolesForResourceRequestToWire(&req) if err != nil { return nil, err } @@ -563,8 +587,8 @@ func (c *internalClient) ListAssignableRolesForResource(ctx context.Context, req // Gets all the roles that can be granted on an account level resource. A role // is grantable if the rule set on the resource can contain an access rule of // the role. -func (c *internalClient) ListAssignableRolesForResourceProxy(ctx context.Context, req *ListAssignableRolesForResourceRequest, opts ...call.Option) (*ListAssignableRolesForResourceResponse, error) { - wireReq, err := listAssignableRolesForResourceRequestToWire(req) +func (c *internalClient) ListAssignableRolesForResourceProxy(ctx context.Context, req ListAssignableRolesForResourceRequest, opts ...call.Option) (*ListAssignableRolesForResourceResponse, error) { + wireReq, err := listAssignableRolesForResourceRequestToWire(&req) if err != nil { return nil, err } @@ -633,8 +657,8 @@ func (c *internalClient) ListAssignableRolesForResourceProxy(ctx context.Context // of the rule set before modifying it. This pattern helps prevent conflicts // between concurrent updates. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdateRuleSet(ctx context.Context, req *UpdateRuleSetRequest, opts ...call.Option) (*RuleSet, error) { - wireReq, err := updateRuleSetRequestToWire(req) +func (c *internalClient) UpdateRuleSet(ctx context.Context, req UpdateRuleSetRequest, opts ...call.Option) (*RuleSet, error) { + wireReq, err := updateRuleSetRequestToWire(&req) if err != nil { return nil, err } @@ -706,8 +730,8 @@ func (c *internalClient) UpdateRuleSet(ctx context.Context, req *UpdateRuleSetRe // Replace the rules of a rule set. First, use get to read the current version // of the rule set before modifying it. This pattern helps prevent conflicts // between concurrent updates. -func (c *internalClient) UpdateRuleSetProxy(ctx context.Context, req *UpdateRuleSetRequest, opts ...call.Option) (*RuleSet, error) { - wireReq, err := updateRuleSetRequestToWire(req) +func (c *internalClient) UpdateRuleSetProxy(ctx context.Context, req UpdateRuleSetRequest, opts ...call.Option) (*RuleSet, error) { + wireReq, err := updateRuleSetRequestToWire(&req) if err != nil { return nil, err } @@ -773,7 +797,7 @@ func (c *internalClient) UpdateRuleSetProxy(ctx context.Context, req *UpdateRule // Gets the permissions of an object. Objects can inherit permissions from their // parent objects or root object. -func (c *internalClient) GetObjectPermissions(ctx context.Context, req *GetObjectPermissionsRequest, opts ...call.Option) (*PermissionsResponse, error) { +func (c *internalClient) GetObjectPermissions(ctx context.Context, req GetObjectPermissionsRequest, opts ...call.Option) (*PermissionsResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -787,9 +811,17 @@ func (c *internalClient) GetObjectPermissions(ctx context.Context, req *GetObjec } pb := pathBuilder{} pb.literal("/api/2.0/permissions/") - pb.singleSegment(*req.RequestObjectType) + if req.RequestObjectType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.RequestObjectType) + } pb.literal("/") - pb.singleSegment(*req.RequestObjectId) + if req.RequestObjectId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.RequestObjectId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -835,7 +867,7 @@ func (c *internalClient) GetObjectPermissions(ctx context.Context, req *GetObjec } // Gets the permission levels that a user can have on an object. -func (c *internalClient) ListPermissionLevels(ctx context.Context, req *ListPermissionLevelsRequest, opts ...call.Option) (*ListPermissionLevelsResponse, error) { +func (c *internalClient) ListPermissionLevels(ctx context.Context, req ListPermissionLevelsRequest, opts ...call.Option) (*ListPermissionLevelsResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -849,9 +881,17 @@ func (c *internalClient) ListPermissionLevels(ctx context.Context, req *ListPerm } pb := pathBuilder{} pb.literal("/api/2.0/permissions/") - pb.singleSegment(*req.RequestObjectType) + if req.RequestObjectType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.RequestObjectType) + } pb.literal("/") - pb.singleSegment(*req.RequestObjectId) + if req.RequestObjectId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.RequestObjectId) + } pb.literal("/permissionLevels") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -900,8 +940,8 @@ func (c *internalClient) ListPermissionLevels(ctx context.Context, req *ListPerm // Sets permissions on an object, replacing existing permissions if they exist. // Deletes all direct permissions if none are specified. Objects can inherit // permissions from their parent objects or root object. -func (c *internalClient) SetObjectPermissions(ctx context.Context, req *SetObjectPermissionsRequest, opts ...call.Option) (*PermissionsResponse, error) { - wireReq, err := setObjectPermissionsRequestToWire(req) +func (c *internalClient) SetObjectPermissions(ctx context.Context, req SetObjectPermissionsRequest, opts ...call.Option) (*PermissionsResponse, error) { + wireReq, err := setObjectPermissionsRequestToWire(&req) if err != nil { return nil, err } @@ -922,9 +962,17 @@ func (c *internalClient) SetObjectPermissions(ctx context.Context, req *SetObjec } pb := pathBuilder{} pb.literal("/api/2.0/permissions/") - pb.singleSegment(*req.RequestObjectType) + if req.RequestObjectType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.RequestObjectType) + } pb.literal("/") - pb.singleSegment(*req.RequestObjectId) + if req.RequestObjectId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.RequestObjectId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -972,8 +1020,8 @@ func (c *internalClient) SetObjectPermissions(ctx context.Context, req *SetObjec // Updates the permissions on an object. Objects can inherit permissions from // their parent objects or root object. -func (c *internalClient) UpdateObjectPermissions(ctx context.Context, req *UpdateObjectPermissionsRequest, opts ...call.Option) (*PermissionsResponse, error) { - wireReq, err := updateObjectPermissionsRequestToWire(req) +func (c *internalClient) UpdateObjectPermissions(ctx context.Context, req UpdateObjectPermissionsRequest, opts ...call.Option) (*PermissionsResponse, error) { + wireReq, err := updateObjectPermissionsRequestToWire(&req) if err != nil { return nil, err } @@ -994,9 +1042,17 @@ func (c *internalClient) UpdateObjectPermissions(ctx context.Context, req *Updat } pb := pathBuilder{} pb.literal("/api/2.0/permissions/") - pb.singleSegment(*req.RequestObjectType) + if req.RequestObjectType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.RequestObjectType) + } pb.literal("/") - pb.singleSegment(*req.RequestObjectId) + if req.RequestObjectId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.RequestObjectId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1043,8 +1099,8 @@ func (c *internalClient) UpdateObjectPermissions(ctx context.Context, req *Updat } // Check access policy to a resource. -func (c *internalClient) CheckPolicy(ctx context.Context, req *CheckPolicyRequest, opts ...call.Option) (*CheckPolicyResponse, error) { - wireReq, err := checkPolicyRequestToWire(req) +func (c *internalClient) CheckPolicy(ctx context.Context, req CheckPolicyRequest, opts ...call.Option) (*CheckPolicyResponse, error) { + wireReq, err := checkPolicyRequestToWire(&req) if err != nil { return nil, err } diff --git a/accessmanagement/v1/genhelper.go b/accessmanagement/v1/genhelper.go old mode 100755 new mode 100644 index b7c91f8..c1ab5b8 --- a/accessmanagement/v1/genhelper.go +++ b/accessmanagement/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/accessmanagement/v1/wire.go b/accessmanagement/v1/wire.go old mode 100755 new mode 100644 index 81d1c38..263571f --- a/accessmanagement/v1/wire.go +++ b/accessmanagement/v1/wire.go @@ -3,9 +3,55 @@ package accessmanagement import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type accessControlRequestWire struct { UserName *string `json:"user_name,omitempty"` GroupName *string `json:"group_name,omitempty"` @@ -91,19 +137,23 @@ func accessControlResponseFromWire(w *accessControlResponseWire) (*AccessControl } type actorWire struct { - ActorId *int64 `json:"actor_id,omitempty"` + ActorId *wireInt64 `json:"actor_id,omitempty"` } func actorToWire(v *Actor) (*actorWire, error) { if v == nil { return nil, nil } - var kindActorIdWire *int64 + var kindActorIdWire *wireInt64 switch value := v.Kind.(type) { case nil: case *Actor_Kind_ActorId: if value != nil { - kindActorIdWire = new(value.ActorId) + kindActorIdConverted, err := int64ToWire(&value.ActorId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Actor.Kind.ActorId", err) + } + kindActorIdWire = kindActorIdConverted } default: return nil, fmt.Errorf("%s: unsupported oneof implementation %T", "Actor.Kind", value) @@ -383,11 +433,11 @@ func permissionsResponseFromWire(w *permissionsResponseWire) (*PermissionsRespon } type principalOutputWire struct { - UserName *string `json:"user_name,omitempty"` - GroupName *string `json:"group_name,omitempty"` - ServicePrincipalName *string `json:"service_principal_name,omitempty"` - PrincipalId *int64 `json:"principal_id,omitempty"` - DisplayName *string `json:"display_name,omitempty"` + UserName *string `json:"user_name,omitempty"` + GroupName *string `json:"group_name,omitempty"` + ServicePrincipalName *string `json:"service_principal_name,omitempty"` + PrincipalId *wireInt64 `json:"principal_id,omitempty"` + DisplayName *string `json:"display_name,omitempty"` } func principalOutputFromWire(w *principalOutputWire) (*PrincipalOutput, error) { @@ -407,6 +457,10 @@ func principalOutputFromWire(w *principalOutputWire) (*PrincipalOutput, error) { if principalNameMembers > 1 { return nil, fmt.Errorf("%s: multiple oneof members set", "PrincipalOutput.PrincipalName") } + principalIdPublicValue, err := int64FromWire(w.PrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PrincipalOutput.PrincipalId", err) + } var principalNameSelection isPrincipalOutput_PrincipalName switch { case w.UserName != nil: @@ -417,7 +471,7 @@ func principalOutputFromWire(w *principalOutputWire) (*PrincipalOutput, error) { principalNameSelection = &PrincipalOutput_PrincipalName_ServicePrincipalName{ServicePrincipalName: *w.ServicePrincipalName} } return &PrincipalOutput{ - PrincipalId: w.PrincipalId, + PrincipalId: principalIdPublicValue, DisplayName: w.DisplayName, PrincipalName: principalNameSelection, }, nil @@ -564,8 +618,8 @@ func updateRuleSetRequestToWire(v *UpdateRuleSetRequest) (*updateRuleSetRequestW type updateWorkspacePermissionAssignmentRequestWire struct { AccountId *string `json:"account_id,omitempty"` - WorkspaceId *int64 `json:"workspace_id,omitempty"` - PrincipalId *int64 `json:"principal_id,omitempty"` + WorkspaceId *wireInt64 `json:"workspace_id,omitempty"` + PrincipalId *wireInt64 `json:"principal_id,omitempty"` Permissions []WorkspacePermission `json:"permissions,omitempty"` } @@ -573,10 +627,18 @@ func updateWorkspacePermissionAssignmentRequestToWire(v *UpdateWorkspacePermissi if v == nil { return nil, nil } + workspaceIdWireValue, err := int64ToWire(v.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateWorkspacePermissionAssignmentRequest.WorkspaceId", err) + } + principalIdWireValue, err := int64ToWire(v.PrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateWorkspacePermissionAssignmentRequest.PrincipalId", err) + } return &updateWorkspacePermissionAssignmentRequestWire{ AccountId: v.AccountId, - WorkspaceId: v.WorkspaceId, - PrincipalId: v.PrincipalId, + WorkspaceId: workspaceIdWireValue, + PrincipalId: principalIdWireValue, Permissions: v.Permissions, }, nil } diff --git a/aigateway/CHANGELOG.md b/aigateway/CHANGELOG.md index 6224c04..19f237c 100644 --- a/aigateway/CHANGELOG.md +++ b/aigateway/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/aigateway/go.mod b/aigateway/go.mod index 3d4b91e..bd4fda8 100644 --- a/aigateway/go.mod +++ b/aigateway/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/aigateway/internal/version.go b/aigateway/internal/version.go index 8af74c7..84b58c9 100644 --- a/aigateway/internal/version.go +++ b/aigateway/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-aigateway" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/aigateway/v1/client.go b/aigateway/v1/client.go old mode 100755 new mode 100644 index 6fe27b7..2e86eed --- a/aigateway/v1/client.go +++ b/aigateway/v1/client.go @@ -83,8 +83,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // `USE_SCHEMA` privileges on the parent schema and `USE_CATALOG` on the parent // catalog. You also need `USE_CONNECTION` on the connection the MCP service // references. -func (c *internalClient) CreateMcpService(ctx context.Context, req *CreateMcpServiceRequest, opts ...call.Option) (*McpService, error) { - wireReq, err := createMcpServiceRequestToWire(req) +func (c *internalClient) CreateMcpService(ctx context.Context, req CreateMcpServiceRequest, opts ...call.Option) (*McpService, error) { + wireReq, err := createMcpServiceRequestToWire(&req) if err != nil { return nil, err } @@ -163,8 +163,8 @@ func (c *internalClient) CreateMcpService(ctx context.Context, req *CreateMcpSer // You must be the owner of the parent schema or have the `CREATE_SERVICE` and // `USE_SCHEMA` privileges on the parent schema and `USE_CATALOG` on the parent // catalog. -func (c *internalClient) CreateModelProviderService(ctx context.Context, req *CreateModelProviderServiceRequest, opts ...call.Option) (*ModelProviderService, error) { - wireReq, err := createModelProviderServiceRequestToWire(req) +func (c *internalClient) CreateModelProviderService(ctx context.Context, req CreateModelProviderServiceRequest, opts ...call.Option) (*ModelProviderService, error) { + wireReq, err := createModelProviderServiceRequestToWire(&req) if err != nil { return nil, err } @@ -241,8 +241,8 @@ func (c *internalClient) CreateModelProviderService(ctx context.Context, req *Cr // You must be the owner of the parent schema or have the `CREATE_SERVICE` and // `USE_SCHEMA` privileges on the parent schema and `USE_CATALOG` on the parent // catalog. -func (c *internalClient) CreateModelService(ctx context.Context, req *CreateModelServiceRequest, opts ...call.Option) (*ModelService, error) { - wireReq, err := createModelServiceRequestToWire(req) +func (c *internalClient) CreateModelService(ctx context.Context, req CreateModelServiceRequest, opts ...call.Option) (*ModelService, error) { + wireReq, err := createModelServiceRequestToWire(&req) if err != nil { return nil, err } @@ -318,8 +318,8 @@ func (c *internalClient) CreateModelService(ctx context.Context, req *CreateMode // // You must be the owner of the MCP service or have `MANAGE` on it, plus // `USE_CATALOG` on the parent catalog and `USE_SCHEMA` on the parent schema. -func (c *internalClient) DeleteMcpService(ctx context.Context, req *DeleteMcpServiceRequest, opts ...call.Option) error { - wireReq, err := deleteMcpServiceRequestToWire(req) +func (c *internalClient) DeleteMcpService(ctx context.Context, req DeleteMcpServiceRequest, opts ...call.Option) error { + wireReq, err := deleteMcpServiceRequestToWire(&req) if err != nil { return err } @@ -336,7 +336,11 @@ func (c *internalClient) DeleteMcpService(ctx context.Context, req *DeleteMcpSer } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "etag", wireReq.Etag); err != nil { @@ -382,8 +386,8 @@ func (c *internalClient) DeleteMcpService(ctx context.Context, req *DeleteMcpSer // You must be the owner of the model provider service or have `MANAGE` on it, // plus `USE_CATALOG` on the parent catalog and `USE_SCHEMA` on the parent // schema. -func (c *internalClient) DeleteModelProviderService(ctx context.Context, req *DeleteModelProviderServiceRequest, opts ...call.Option) error { - wireReq, err := deleteModelProviderServiceRequestToWire(req) +func (c *internalClient) DeleteModelProviderService(ctx context.Context, req DeleteModelProviderServiceRequest, opts ...call.Option) error { + wireReq, err := deleteModelProviderServiceRequestToWire(&req) if err != nil { return err } @@ -400,7 +404,11 @@ func (c *internalClient) DeleteModelProviderService(ctx context.Context, req *De } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "etag", wireReq.Etag); err != nil { @@ -445,8 +453,8 @@ func (c *internalClient) DeleteModelProviderService(ctx context.Context, req *De // // You must be the owner of the model service or have `MANAGE` on it, plus // `USE_CATALOG` on the parent catalog and `USE_SCHEMA` on the parent schema. -func (c *internalClient) DeleteModelService(ctx context.Context, req *DeleteModelServiceRequest, opts ...call.Option) error { - wireReq, err := deleteModelServiceRequestToWire(req) +func (c *internalClient) DeleteModelService(ctx context.Context, req DeleteModelServiceRequest, opts ...call.Option) error { + wireReq, err := deleteModelServiceRequestToWire(&req) if err != nil { return err } @@ -463,7 +471,11 @@ func (c *internalClient) DeleteModelService(ctx context.Context, req *DeleteMode } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "etag", wireReq.Etag); err != nil { @@ -507,7 +519,7 @@ func (c *internalClient) DeleteModelService(ctx context.Context, req *DeleteMode // You must be the owner of the MCP service or have `EXECUTE`, `READ_METADATA`, // or `MANAGE` on it, plus `USE_CATALOG` on the parent catalog and `USE_SCHEMA` // on the parent schema. -func (c *internalClient) GetMcpService(ctx context.Context, req *GetMcpServiceRequest, opts ...call.Option) (*McpService, error) { +func (c *internalClient) GetMcpService(ctx context.Context, req GetMcpServiceRequest, opts ...call.Option) (*McpService, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -521,7 +533,11 @@ func (c *internalClient) GetMcpService(ctx context.Context, req *GetMcpServiceRe } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -571,7 +587,7 @@ func (c *internalClient) GetMcpService(ctx context.Context, req *GetMcpServiceRe // You must be the owner of the model provider service or have `EXECUTE`, // `READ_METADATA`, or `MANAGE` on it, plus `USE_CATALOG` on the parent catalog // and `USE_SCHEMA` on the parent schema. -func (c *internalClient) GetModelProviderService(ctx context.Context, req *GetModelProviderServiceRequest, opts ...call.Option) (*ModelProviderService, error) { +func (c *internalClient) GetModelProviderService(ctx context.Context, req GetModelProviderServiceRequest, opts ...call.Option) (*ModelProviderService, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -585,7 +601,11 @@ func (c *internalClient) GetModelProviderService(ctx context.Context, req *GetMo } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -635,7 +655,7 @@ func (c *internalClient) GetModelProviderService(ctx context.Context, req *GetMo // You must be the owner of the model service or have `EXECUTE`, // `READ_METADATA`, or `MANAGE` on it, plus `USE_CATALOG` on the parent catalog // and `USE_SCHEMA` on the parent schema. -func (c *internalClient) GetModelService(ctx context.Context, req *GetModelServiceRequest, opts ...call.Option) (*ModelService, error) { +func (c *internalClient) GetModelService(ctx context.Context, req GetModelServiceRequest, opts ...call.Option) (*ModelService, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -649,7 +669,11 @@ func (c *internalClient) GetModelService(ctx context.Context, req *GetModelServi } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -701,8 +725,8 @@ func (c *internalClient) GetModelService(ctx context.Context, req *GetModelServi // Requires `USE_CATALOG` on the parent catalog and `USE_SCHEMA` on the parent // schema. Only MCP services the caller can access (as owner or through // `EXECUTE`, `READ_METADATA`, or `MANAGE`) are returned. -func (c *internalClient) ListMcpServices(ctx context.Context, req *ListMcpServicesRequest, opts ...call.Option) (*ListMcpServicesResponse, error) { - wireReq, err := listMcpServicesRequestToWire(req) +func (c *internalClient) ListMcpServices(ctx context.Context, req ListMcpServicesRequest, opts ...call.Option) (*ListMcpServicesResponse, error) { + wireReq, err := listMcpServicesRequestToWire(&req) if err != nil { return nil, err } @@ -780,7 +804,7 @@ func (c *internalClient) ListMcpServices(ctx context.Context, req *ListMcpServic // // For example: // -// for item, err := range c.ListMcpServicesIter(ctx, &ListMcpServicesRequest{}) { +// for item, err := range c.ListMcpServicesIter(ctx, ListMcpServicesRequest{}) { // if err != nil { // return err // } @@ -792,16 +816,13 @@ func (c *internalClient) ListMcpServices(ctx context.Context, req *ListMcpServic // // Callers who need custom pagination logic should use // ListMcpServices directly. -func (c *internalClient) ListMcpServicesIter(ctx context.Context, req *ListMcpServicesRequest, opts ...call.Option) iter.Seq2[*McpService, error] { +func (c *internalClient) ListMcpServicesIter(ctx context.Context, req ListMcpServicesRequest, opts ...call.Option) iter.Seq2[*McpService, error] { return func(yield func(*McpService, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListMcpServicesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListMcpServices(ctx, &pageReq, opts...) + resp, err := c.ListMcpServices(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -826,8 +847,8 @@ func (c *internalClient) ListMcpServicesIter(ctx context.Context, req *ListMcpSe // Requires `USE_CATALOG` on the parent catalog and `USE_SCHEMA` on the parent // schema. Only model provider services the caller can access (as owner or // through `EXECUTE`, `READ_METADATA`, or `MANAGE`) are returned. -func (c *internalClient) ListModelProviderServices(ctx context.Context, req *ListModelProviderServicesRequest, opts ...call.Option) (*ListModelProviderServicesResponse, error) { - wireReq, err := listModelProviderServicesRequestToWire(req) +func (c *internalClient) ListModelProviderServices(ctx context.Context, req ListModelProviderServicesRequest, opts ...call.Option) (*ListModelProviderServicesResponse, error) { + wireReq, err := listModelProviderServicesRequestToWire(&req) if err != nil { return nil, err } @@ -905,7 +926,7 @@ func (c *internalClient) ListModelProviderServices(ctx context.Context, req *Lis // // For example: // -// for item, err := range c.ListModelProviderServicesIter(ctx, &ListModelProviderServicesRequest{}) { +// for item, err := range c.ListModelProviderServicesIter(ctx, ListModelProviderServicesRequest{}) { // if err != nil { // return err // } @@ -917,16 +938,13 @@ func (c *internalClient) ListModelProviderServices(ctx context.Context, req *Lis // // Callers who need custom pagination logic should use // ListModelProviderServices directly. -func (c *internalClient) ListModelProviderServicesIter(ctx context.Context, req *ListModelProviderServicesRequest, opts ...call.Option) iter.Seq2[*ModelProviderService, error] { +func (c *internalClient) ListModelProviderServicesIter(ctx context.Context, req ListModelProviderServicesRequest, opts ...call.Option) iter.Seq2[*ModelProviderService, error] { return func(yield func(*ModelProviderService, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListModelProviderServicesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListModelProviderServices(ctx, &pageReq, opts...) + resp, err := c.ListModelProviderServices(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -951,8 +969,8 @@ func (c *internalClient) ListModelProviderServicesIter(ctx context.Context, req // Requires `USE_CATALOG` on the parent catalog and `USE_SCHEMA` on the parent // schema. Only model services the caller can access (as owner or through // `EXECUTE`, `READ_METADATA`, or `MANAGE`) are returned. -func (c *internalClient) ListModelServices(ctx context.Context, req *ListModelServicesRequest, opts ...call.Option) (*ListModelServicesResponse, error) { - wireReq, err := listModelServicesRequestToWire(req) +func (c *internalClient) ListModelServices(ctx context.Context, req ListModelServicesRequest, opts ...call.Option) (*ListModelServicesResponse, error) { + wireReq, err := listModelServicesRequestToWire(&req) if err != nil { return nil, err } @@ -1030,7 +1048,7 @@ func (c *internalClient) ListModelServices(ctx context.Context, req *ListModelSe // // For example: // -// for item, err := range c.ListModelServicesIter(ctx, &ListModelServicesRequest{}) { +// for item, err := range c.ListModelServicesIter(ctx, ListModelServicesRequest{}) { // if err != nil { // return err // } @@ -1042,16 +1060,13 @@ func (c *internalClient) ListModelServices(ctx context.Context, req *ListModelSe // // Callers who need custom pagination logic should use // ListModelServices directly. -func (c *internalClient) ListModelServicesIter(ctx context.Context, req *ListModelServicesRequest, opts ...call.Option) iter.Seq2[*ModelService, error] { +func (c *internalClient) ListModelServicesIter(ctx context.Context, req ListModelServicesRequest, opts ...call.Option) iter.Seq2[*ModelService, error] { return func(yield func(*ModelService, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListModelServicesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListModelServices(ctx, &pageReq, opts...) + resp, err := c.ListModelServices(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1075,8 +1090,8 @@ func (c *internalClient) ListModelServicesIter(ctx context.Context, req *ListMod // // You must be the owner of the MCP service or have `MANAGE` on it, plus // `USE_CATALOG` on the parent catalog and `USE_SCHEMA` on the parent schema. -func (c *internalClient) UpdateMcpService(ctx context.Context, req *UpdateMcpServiceRequest, opts ...call.Option) (*McpService, error) { - wireReq, err := updateMcpServiceRequestToWire(req) +func (c *internalClient) UpdateMcpService(ctx context.Context, req UpdateMcpServiceRequest, opts ...call.Option) (*McpService, error) { + wireReq, err := updateMcpServiceRequestToWire(&req) if err != nil { return nil, err } @@ -1097,7 +1112,11 @@ func (c *internalClient) UpdateMcpService(ctx context.Context, req *UpdateMcpSer } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/") - pb.singleSegment(*req.McpService.Name) + if req.McpService == nil || req.McpService.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.McpService.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -1157,8 +1176,8 @@ func (c *internalClient) UpdateMcpService(ctx context.Context, req *UpdateMcpSer // You must be the owner of the model provider service or have `MANAGE` on it, // plus `USE_CATALOG` on the parent catalog and `USE_SCHEMA` on the parent // schema. -func (c *internalClient) UpdateModelProviderService(ctx context.Context, req *UpdateModelProviderServiceRequest, opts ...call.Option) (*ModelProviderService, error) { - wireReq, err := updateModelProviderServiceRequestToWire(req) +func (c *internalClient) UpdateModelProviderService(ctx context.Context, req UpdateModelProviderServiceRequest, opts ...call.Option) (*ModelProviderService, error) { + wireReq, err := updateModelProviderServiceRequestToWire(&req) if err != nil { return nil, err } @@ -1179,7 +1198,11 @@ func (c *internalClient) UpdateModelProviderService(ctx context.Context, req *Up } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/") - pb.singleSegment(*req.ModelProviderService.Name) + if req.ModelProviderService == nil || req.ModelProviderService.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ModelProviderService.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -1237,8 +1260,8 @@ func (c *internalClient) UpdateModelProviderService(ctx context.Context, req *Up // // You must be the owner of the model service or have `MANAGE` on it, plus // `USE_CATALOG` on the parent catalog and `USE_SCHEMA` on the parent schema. -func (c *internalClient) UpdateModelService(ctx context.Context, req *UpdateModelServiceRequest, opts ...call.Option) (*ModelService, error) { - wireReq, err := updateModelServiceRequestToWire(req) +func (c *internalClient) UpdateModelService(ctx context.Context, req UpdateModelServiceRequest, opts ...call.Option) (*ModelService, error) { + wireReq, err := updateModelServiceRequestToWire(&req) if err != nil { return nil, err } @@ -1259,7 +1282,11 @@ func (c *internalClient) UpdateModelService(ctx context.Context, req *UpdateMode } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/") - pb.singleSegment(*req.ModelService.Name) + if req.ModelService == nil || req.ModelService.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ModelService.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { diff --git a/aigateway/v1/genhelper.go b/aigateway/v1/genhelper.go old mode 100755 new mode 100644 index 6d3e11c..9bb02ec --- a/aigateway/v1/genhelper.go +++ b/aigateway/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/aigateway/v1/model.go b/aigateway/v1/model.go old mode 100755 new mode 100644 index 25a1f7c..ac5cb5c --- a/aigateway/v1/model.go +++ b/aigateway/v1/model.go @@ -49,29 +49,11 @@ const ( // inference-table details) and rate-limit principal names. ListModelServicesRequest_View_Full ListModelServicesRequest_View = "FULL" // Envelope only: identifiers, ownership, timestamps, plus the persisted - // `config` scalars (`routing_strategy`, `rate_limits` without `principal`); + // `config` scalars (`first_token_timeout`, `rate_limits` without `principal`); // `destinations` and the inference-table details are unset. ListModelServicesRequest_View_Basic ListModelServicesRequest_View = "BASIC" ) -// Which Anthropic subscription tier the relayed OAuth token belongs to. -// Immutable after Create (switching tiers changes which governance controls the -// platform enforces). Only MAX and TEAM_ENTERPRISE differ in the governance -// surface the gateway can enforce, not in how the token is relayed. -type ModelProviderServiceConfig_AnthropicProviderRelayedConfig_AnthropicRelayedPlanType string - -const ( - ModelProviderServiceConfig_AnthropicProviderRelayedConfig_AnthropicRelayedPlanType_Unspecified ModelProviderServiceConfig_AnthropicProviderRelayedConfig_AnthropicRelayedPlanType = "" - // Personal Claude Max/Pro subscription. No gateway-enforced governance: model - // selection, per-principal rate limits, and service policies (guard- rails) - // cannot be enforced on a personal subscription and are rejected. - ModelProviderServiceConfig_AnthropicProviderRelayedConfig_AnthropicRelayedPlanType_AnthropicRelayedPlanTypeMax ModelProviderServiceConfig_AnthropicProviderRelayedConfig_AnthropicRelayedPlanType = "ANTHROPIC_RELAYED_PLAN_TYPE_MAX" - // Claude for Teams / Enterprise organization subscription. Supports the full - // gateway governance surface: model allowlist (`targets` / - // `allow_all_targets`), rate limits, and service policies. - ModelProviderServiceConfig_AnthropicProviderRelayedConfig_AnthropicRelayedPlanType_AnthropicRelayedPlanTypeTeamEnterprise ModelProviderServiceConfig_AnthropicProviderRelayedConfig_AnthropicRelayedPlanType = "ANTHROPIC_RELAYED_PLAN_TYPE_TEAM_ENTERPRISE" -) - // External LLM provider for an EXTERNAL_FOUNDATION_MODEL destination. type ModelProviderServiceConfig_ExternalModelProviderType string @@ -89,7 +71,8 @@ const ( // Custom OpenAI-compatible provider (any endpoint that speaks the OpenAI HTTP // API). Configured by `base_url` + API key. ModelProviderServiceConfig_ExternalModelProviderType_ExternalModelProviderTypeCustom ModelProviderServiceConfig_ExternalModelProviderType = "EXTERNAL_MODEL_PROVIDER_TYPE_CUSTOM" - // Microsoft AI Foundry. Auth via API key plus Foundry endpoint URL. + // Microsoft Foundry. Configure a Foundry endpoint URL and authentication + // credentials. ModelProviderServiceConfig_ExternalModelProviderType_ExternalModelProviderTypeMicrosoftFoundry ModelProviderServiceConfig_ExternalModelProviderType = "EXTERNAL_MODEL_PROVIDER_TYPE_MICROSOFT_FOUNDRY" // Google Gemini Enterprise. Auth via API key. ModelProviderServiceConfig_ExternalModelProviderType_ExternalModelProviderTypeGeminiEnterprise ModelProviderServiceConfig_ExternalModelProviderType = "EXTERNAL_MODEL_PROVIDER_TYPE_GEMINI_ENTERPRISE" @@ -149,7 +132,8 @@ type CreateMcpServiceRequest struct { // Name for the MCP service, e.g. "my_mcp_service". McpServiceId *string // The MCP service to create. The server populates `name` from `parent` + - // `mcp_service_id`; clients should leave it unset. + // `mcp_service_id`; clients should leave it unset. `source_connection` is + // required. McpService *McpService } @@ -183,8 +167,10 @@ type DeleteMcpServiceRequest struct { // `mcp-services/{catalog}.{schema}.{mcp_service}`. Each `{...}` component is // capped at 255 characters individually. Name *string - // If-match precondition: when set, the delete proceeds only if the current - // server-side etag matches. Empty means unconditional delete. + // Optimistic concurrency token from the most recent read. When set, the delete + // succeeds only if the resource has not changed. Leave unset for an + // unconditional delete. For REST requests, URL-encode the base64 string + // returned by the API when setting the `etag` query parameter. Etag []byte } @@ -194,8 +180,10 @@ type DeleteModelProviderServiceRequest struct { // `model-provider-services/{catalog}.{schema}.{model_provider_service}`. Each // `{...}` component is capped at 255 characters individually. Name *string - // If-match precondition: when set, the delete proceeds only if the current - // server-side etag matches. Empty means unconditional delete. + // Optimistic concurrency token from the most recent read. When set, the delete + // succeeds only if the resource has not changed. Leave unset for an + // unconditional delete. For REST requests, URL-encode the base64 string + // returned by the API when setting the `etag` query parameter. Etag []byte } @@ -205,8 +193,10 @@ type DeleteModelServiceRequest struct { // `model-services/{catalog}.{schema}.{model_service}`. Each `{...}` component // is capped at 255 characters individually. Name *string - // If-match precondition: when set, the delete proceeds only if the current - // server-side etag matches. Empty means unconditional delete. + // Optimistic concurrency token from the most recent read. When set, the delete + // succeeds only if the resource has not changed. Leave unset for an + // unconditional delete. For REST requests, URL-encode the base64 string + // returned by the API when setting the `etag` query parameter. Etag []byte } @@ -246,20 +236,12 @@ type InferenceTableConfig struct { // `schemas/{catalog}.{schema}`. Set at create time and immutable thereafter; // changing it on an existing service is rejected. Parent *string `fieldmask:"parent"` - // Prefix for the inference-table's UC-registered name. The actual leaf name UC - // stores is `_payload`; the `_payload` suffix is appended - // automatically. To find the actual UC table after Create, read the `table` - // field on the response. Defaults to `_payload` when unset. - // Set at create time and immutable thereafter; changing it on an existing - // service is rejected. + // Prefix used to form the inference table's registered name. AI Gateway appends + // `_payload`; for example, `table_name_prefix = "orders"` creates + // `orders_payload`. If unset, the prefix defaults to the service name. Read + // `table` from the response for the resolved resource name. Set at create time + // and immutable thereafter. TableNamePrefix *string `fieldmask:"table_name_prefix"` - // Indicates whether payload logging is disabled (opt-out). Unset means that - // payload logging is active (the on-by-default state coincides with the proto - // zero-value, so the server never fills this field for a client that leaves it - // unset). Set `disabled = true` to pause runtime logging while keeping the - // sub-message attached (preserving `parent` and `table_name_prefix` for a later - // flip back to active). `parent` remains required either way. - Disabled *bool `fieldmask:"disabled"` // Resolved UC table for payload logs. Format: // `tables/{catalog}.{schema}.{table}`. Table *string `fieldmask:"table"` @@ -273,17 +255,18 @@ type InferenceTableConfig struct { // Request to list MCP services. Accepts `parent`, `page_size`, and // `page_token`.. type ListMcpServicesRequest struct { - // Name of the parent schema to list within, as `schemas/{catalog}.{schema}`. - // Each `{...}` component is capped at 255 characters individually. + // Parent schema to list within, in the form `schemas/{catalog}.{schema}`. + // Required. Each `{...}` component is capped at 255 characters individually. Parent *string // Maximum number of MCP services to return. Defaults to 100 when unset or 0; // the maximum is 100. Use `page_token` to retrieve additional pages. PageSize *int // Opaque pagination token from a previous request. PageToken *string - // View selector controlling which fields are populated per row. `FULL` returns - // the full representation of the service; `BASIC` returns a more compact - // version. Defaults to `BASIC` when unset. + // Fields to return for each service. `FULL` includes source-connection details + // and rate-limit principal names. `BASIC` omits the source connection and omits + // principal names from rate limits. Defaults to `BASIC` when unset or + // `VIEW_UNSPECIFIED`. View ListMcpServicesRequest_View } @@ -298,17 +281,18 @@ type ListMcpServicesResponse struct { // Request to list model provider services. Accepts `parent`, `page_size`, and // `page_token`.. type ListModelProviderServicesRequest struct { - // Name of the parent schema to list within, as `schemas/{catalog}.{schema}`. - // Each `{...}` component is capped at 255 characters individually. + // Parent schema to list within, in the form `schemas/{catalog}.{schema}`. + // Required. Each `{...}` component is capped at 255 characters individually. Parent *string // Maximum number of provider services to return. Defaults to 100 when unset or // 0; the maximum is 100. Use `page_token` to retrieve additional pages. PageSize *int // Opaque pagination token from a previous request. PageToken *string - // View selector controlling which fields are populated per row. `FULL` returns - // the full representation of the service; `BASIC` returns a more compact - // version. Defaults to `BASIC` when unset. + // Fields to return for each service. `FULL` includes inference-table details + // and rate-limit principal names. `BASIC` omits inference-table details and + // omits principal names from rate limits. Defaults to `BASIC` when unset or + // `VIEW_UNSPECIFIED`. View ListModelProviderServicesRequest_View } @@ -323,17 +307,18 @@ type ListModelProviderServicesResponse struct { // Request to list model services. Accepts `parent`, `page_size`, and // `page_token`.. type ListModelServicesRequest struct { - // Name of the parent schema to list within, as `schemas/{catalog}.{schema}`. - // Each `{...}` component is capped at 255 characters individually. + // Parent schema to list within, in the form `schemas/{catalog}.{schema}`. + // Required. Each `{...}` component is capped at 255 characters individually. Parent *string // Maximum number of model services to return. Defaults to 100 when unset or 0; // the maximum is 100. Use `page_token` to retrieve additional pages. PageSize *int // Opaque pagination token from a previous request. PageToken *string - // View selector controlling which fields are populated per row. `FULL` returns - // the full representation of the service; `BASIC` returns a more compact - // version. Defaults to `BASIC` when unset. + // Fields to return for each service. `FULL` includes destinations, + // inference-table details, and rate-limit principal names. `BASIC` omits + // destinations and inference-table details and omits principal names from rate + // limits. Defaults to `BASIC` when unset or `VIEW_UNSPECIFIED`. View ListModelServicesRequest_View } @@ -345,47 +330,43 @@ type ListModelServicesResponse struct { NextPageToken *string } -// A governed MCP server registration in Unity Catalog. Acts as a container -// securable that references an MCP server -- customer-external via a UC -// Connection, or -hosted via an internal server -- and exposes its -// tools for discovery, authorization, and invocation.. +// A Unity Catalog securable that registers an MCP server through a Unity +// Catalog connection and exposes its tools for discovery, authorization, and +// invocation.. type McpService struct { // Resource name of the MCP service. Format: // `mcp-services/{catalog}.{schema}.{mcp_service}`. Each `{...}` component is // capped at 255 characters individually. Server-derived on Create from `parent` // + `mcp_service_id`; required and immutable on Update/Get/Delete. Name *string `fieldmask:"name"` - // The owner of the MCP service. Write-only; read owner via effective_owner. - Owner *string `fieldmask:"owner"` // The resolved owner of the MCP service. Falls back to the caller's identity // when `owner` is not explicitly set on creation. EffectiveOwner *string `fieldmask:"effective_owner"` // Metastore hosting the MCP service. MetastoreId *string `fieldmask:"metastore_id"` - // When the MCP service was created. + // Time the MCP service was created. CreateTime *types.Time `fieldmask:"create_time"` // Creator identity. CreatedBy *string `fieldmask:"created_by"` - // When the MCP service was last modified. + // Time the MCP service was last modified. UpdateTime *types.Time `fieldmask:"update_time"` // Identity of the last updater. UpdatedBy *string `fieldmask:"updated_by"` // User-provided description. Comment *string `fieldmask:"comment"` - // Operational configuration: connection, tool selectors, rate limit. Required - // on CreateMcpService; on UpdateMcpService it is required only when `config` - // (or a `config.*` subpath) appears in `update_mask`. + // Connection, tool selectors, and rate limits. Required on Create. On Update, + // provide this field when `update_mask` contains `config` or one of its + // subpaths. Config *McpServiceConfig `fieldmask:"config"` - // Optimistic concurrency control token. Server-generated from the entity's - // state and returned on every read. To use it as an if-match precondition on a - // mutation, echo the last-read value back via the dedicated `etag` field on the - // Update / Delete request; the server rejects the mutation if the stored etag - // differs. + // Optimistic concurrency token returned on every read. To make an Update or + // Delete conditional, pass the last-read value in that request's `etag` field. + // In REST responses, this value is a base64 string; URL-encode it when setting + // the `etag` query parameter. Etag []byte `fieldmask:"etag"` } // Operational configuration for an MCP service. Groups the source reference, -// tool selectors, and rate limit -- the fields that configure how the MCP +// tool selectors, and rate limits -- the fields that configure how the MCP // service behaves at invocation time.. type McpServiceConfig struct { // Polymorphic reference to where the MCP server lives. MCP_SERVICE is a @@ -403,15 +384,13 @@ type McpServiceConfig struct { // (-- The oneof shape lets future kinds add type-specific reference shapes // without a wire-format bump. --) Source isMcpServiceConfig_Source - // Glob or exact-match patterns selecting which tools from the MCP server to - // expose. Prefix match for patterns with `*`, exact match otherwise. An empty - // list means all tools are included. Per-element max 256 chars. + // Tool names or prefix patterns to expose from the MCP server. Use exact tool + // names or prefix patterns such as `read_*`. An empty list exposes all tools. + // Each selector can contain at most 256 characters. IncludeToolSelectors []string `fieldmask:"include_tool_selectors"` - // Per-principal rate limits applied to tool invocations routed through this MCP - // service. Repeated to support per-USER / USER_GROUP / SERVICE_PRINCIPAL / - // SERVICE / USER_DEFAULT scopes simultaneously, mirroring the - // `ModelServiceConfig.rate_limits` shape. Empty when no rate limit is - // configured. + // Rate limits for tool invocations, scoped to a user, group, service principal, + // the service as a whole, or each user by default. Request-tag rate limits are + // not supported for MCP services. Empty when no rate limit is configured. RateLimits []RateLimit `fieldmask:"rate_limits"` _ [0]mcpServiceConfigSourceFieldMaskMetadata `fieldmask_oneof:"Source"` } @@ -421,7 +400,7 @@ type isMcpServiceConfig_Source interface { } // McpServiceConfig_Source_SourceConnection selects SourceConnection for McpServiceConfig.Source. -// UC Connection referencing the MCP server. +// Unity Catalog connection referencing the MCP server. Required on Create. type McpServiceConfig_Source_SourceConnection struct { SourceConnection McpServiceConfig_SourceConnection `fieldmask:"source_connection"` } @@ -432,22 +411,24 @@ type mcpServiceConfigSourceFieldMaskMetadata struct { *McpServiceConfig_Source_SourceConnection } -// UC Connection that hosts the MCP server. On create, provide `name` in the -// schema-scoped form `connections/{catalog}.{schema}.{connection}`. On read, -// the service populates the resolved connection metadata and preserves a +// Unity Catalog connection that hosts the MCP server. On Create, provide `name` +// in the schema-scoped form `connections/{catalog}.{schema}.{connection}`. On +// read, the service populates the resolved connection metadata and preserves a // dangling source so callers can diagnose a deleted backing connection.. type McpServiceConfig_SourceConnection struct { - // Name of the UC connection that hosts the MCP server, as + // Name of the Unity Catalog connection that hosts the MCP server, as // `connections/{catalog}.{schema}.{connection}`. - Name *string `fieldmask:"name"` - IsDeleted *bool `fieldmask:"is_deleted"` + Name *string `fieldmask:"name"` + // Whether the referenced connection has been deleted. The MCP service keeps the + // reference so callers can identify the broken dependency; tool invocation + // fails until the source connection is updated. + IsDeleted *bool `fieldmask:"is_deleted"` } -// A governed external model-provider connection stored in Unity Catalog (e.g. -// an OpenAI API account, an Azure OpenAI deployment, an Amazon Bedrock -// account). Owns the provider type and the auth/configuration the platform -// needs to invoke that provider, and is referenced from -// `ExternalModelConfig.model_provider_service` on a ModelService. +// A governed connection to an external model provider stored in Unity Catalog, +// such as an OpenAI account, Azure OpenAI deployment, or Amazon Bedrock +// account. It stores the provider type, authentication, and connection +// configuration used by model service destinations. // // One ModelProviderService can back many ModelServices (e.g. an `openai_prod` // provider serving multiple models); a single ModelService can fan out across @@ -459,34 +440,29 @@ type ModelProviderService struct { // Create from `parent` + `model_provider_service_id`; required and immutable on // Update/Get/Delete. Name *string `fieldmask:"name"` - // The owner of the model provider service. Write-only; read owner via - // effective_owner. - Owner *string `fieldmask:"owner"` // The resolved owner of the model provider service. Falls back to the caller's // identity when `owner` is not explicitly set on creation. EffectiveOwner *string `fieldmask:"effective_owner"` // Metastore hosting the provider service. MetastoreId *string `fieldmask:"metastore_id"` - // When the provider service was created. + // Time the provider service was created. CreateTime *types.Time `fieldmask:"create_time"` // Creator identity. CreatedBy *string `fieldmask:"created_by"` - // When the provider service was last modified. + // Time the provider service was last modified. UpdateTime *types.Time `fieldmask:"update_time"` // Identity of the last updater. UpdatedBy *string `fieldmask:"updated_by"` // User-provided description. Comment *string `fieldmask:"comment"` - // Optimistic concurrency control token. Server-generated from the entity's - // state and returned on every read. To use it as an if-match precondition on a - // mutation, echo the last-read value back via the dedicated `etag` field on the - // Update / Delete request; the server rejects the mutation if the stored etag - // differs. + // Optimistic concurrency token returned on every read. To make an Update or + // Delete conditional, pass the last-read value in that request's `etag` field. + // In REST responses, this value is a base64 string; URL-encode it when setting + // the `etag` query parameter. Etag []byte `fieldmask:"etag"` - // Behavioral configuration: provider connection, model catalog, and passthrough - // policy. See `ModelProviderServiceConfig` for the per-field contract. Required - // on CreateModelProviderService; on Update it is required only when `config` - // (or a `config.*` subpath) appears in `update_mask`. + // Provider connection, exposed models, request-forwarding controls, rate + // limits, and payload logging. Required on Create. On Update, it is required + // only when `config` or one of its subpaths appears in `update_mask`. Config *ModelProviderServiceConfig `fieldmask:"config"` } @@ -506,13 +482,13 @@ type ModelProviderServiceConfig struct { // Provider-specific configuration. Exactly one variant must be set, and it must // match `provider_type`; a request whose active variant disagrees with // `provider_type` is rejected with `INVALID_PARAMETER_VALUE`. Secret-bearing - // fields nested inside each *DirectConfig (`api_key`, `aws_secret_access_key`, + // fields nested inside each *DirectConfig (`api_key`, `secret_access_key`, // `service_account_key`, ...) wrap a `ProviderSecret`: callers supply the value // as `ProviderSecret.plaintext` on writes, and the platform stores it // encrypted. Reads (Get and List) omit the plaintext; secret-bearing fields // appear in the response only as a presence indicator that a secret is // configured. Non-secret fields (`base_url`, `region`, `organization`, - // `aws_access_key_id`, ...) round-trip directly. + // `access_key_id`, ...) round-trip directly. // // Declarative tooling (Terraform / DABs): the `plaintext` field is INPUT_ONLY // and never round-trips on reads, so a Terraform config that supplies it will @@ -542,37 +518,34 @@ type ModelProviderServiceConfig struct { // not required and does not restrict routability. When false, only models // listed in `targets` are routable. AllowAllTargets *bool `fieldmask:"allow_all_targets"` - // Routing targets this provider service exposes (provider-side model identifier - // + unified API types per entry). Required (>=1) when `allow_all_targets = - // false`; optional and additive when `allow_all_targets = true`. References - // from `ExternalModelConfig.target` must match an entry here unless - // `allow_all_targets = true`. + // Models and provider-native API types exposed by this provider service. Each + // entry must include at least one `native_api_types` value. When + // `allow_all_targets` is false, at least one entry is required and model + // service destinations can reference only listed models. When + // `allow_all_targets` is true, any upstream model is routable; entries in this + // list provide API-type metadata without restricting other models. Targets []ModelProviderServiceConfig_ModelTargetConfig `fieldmask:"targets"` - // Whether to forward incoming request headers to the upstream provider. Applies - // to managed (multi-model) requests as well as passthrough requests served by - // this provider service. Governance-level decision by the provider service - // owner; not selectable per inference call. + // Whether to forward incoming HTTP headers to the upstream provider. Applies to + // translated and passthrough requests and is configured for the entire provider + // service, not per request. Upstream authentication is configured separately in + // `provider`. ForwardHeaders *bool `fieldmask:"forward_headers"` - // Whether to forward incoming request query parameters to the upstream - // provider. Same trust-boundary semantics as `forward_headers`. + // Whether incoming query parameters are forwarded to the upstream provider. + // Applies to translated and passthrough requests and is configured for the + // entire provider service, not per request. ForwardQueryParameters *bool `fieldmask:"forward_query_parameters"` - // Whether to forward request paths that fall outside this service's managed API - // set to the upstream provider as opaque passthrough. When true, requests - // addressed to subpaths not recognized by the managed API surface are proxied - // to the upstream provider over the same provider connection. When false, only - // managed-API paths are served. Governance-level decision by the provider - // service owner; expanding this expands the trust boundary that the - // ModelProviderService exposes. + // Whether to proxy paths that AI Gateway does not recognize as configured + // provider-native API types. When true, these paths are forwarded unchanged + // over the provider connection. When false, only recognized API paths are + // served. Enabling this broadens the upstream API surface exposed through the + // provider service. ForwardUnmanagedPaths *bool `fieldmask:"forward_unmanaged_paths"` - // Rate limits applied when this provider service is invoked directly. When it - // is invoked through a model service, the model service's own `rate_limits` - // apply instead. Mirrors `ModelServiceConfig.rate_limits` / - // `McpServiceConfig.rate_limits`. + // Rate limits for requests sent directly to this provider service. Requests + // routed through a model service use that model service's rate limits instead. RateLimits []RateLimit `fieldmask:"rate_limits"` - // Inference table configuration for payload logging when this provider service - // is invoked directly. When it is invoked through a model service, the model - // service's own inference table captures the invocation instead. Mirrors - // `ModelServiceConfig.inference_table` / `AgentServiceConfig.inference_table`. + // Payload logging configuration for requests sent directly to this provider + // service. Requests routed through a model service are captured by that model + // service's inference table instead. InferenceTable *InferenceTableConfig `fieldmask:"inference_table"` _ [0]modelProviderServiceConfigProviderFieldMaskMetadata `fieldmask_oneof:"Provider"` } @@ -673,11 +646,11 @@ type modelProviderServiceConfig_AmazonBedrockProviderConfigProviderModeFieldMask // // Authentication is one of two mutually exclusive modes, exactly one of which // must be supplied on Create: - Access keys: set `aws_access_key`, leave -// `service_credential` unset. - UC service credential: set -// `service_credential.name` to the AIP-122 resource-name form -// `credentials/{name}`, leave `aws_access_key` unset. The credential value -// lives in UC and is referenced by name, not held on this message. Setting more -// than one mode is rejected.. +// `service_credential` unset. - Unity Catalog service credential: set +// `service_credential.name` to the resource name `credentials/{name}`, leave +// `aws_access_key` unset. The credential value lives in Unity Catalog and is +// referenced by name, not held on this message. Setting more than one mode is +// rejected.. type ModelProviderServiceConfig_AmazonBedrockProviderDirectConfig struct { // AWS region where the Bedrock endpoint is hosted (e.g., `us-east-1`). Required // on Create. @@ -692,14 +665,13 @@ type isModelProviderServiceConfig_AmazonBedrockProviderDirectConfig_AuthMode int } // ModelProviderServiceConfig_AmazonBedrockProviderDirectConfig_AuthMode_ServiceCredential selects ServiceCredential for ModelProviderServiceConfig_AmazonBedrockProviderDirectConfig.AuthMode. -// Reference to a UC service credential authorizing Bedrock requests. On Create -// the caller supplies `service_credential.name` in the AIP-122 resource-name -// form `credentials/{name}`. Required on Create when using -// UC-service-credential auth; mutually exclusive with `aws_access_key`. The -// credential is referenced by name; its value is not carried here. On read the -// resolved `id` and `is_deleted` are also populated. Only supported on -// AWS-hosted workspaces; Create requests from other clouds are rejected with -// INVALID_PARAMETER_VALUE. +// Reference to a Unity Catalog service credential authorizing Bedrock requests. +// On Create, supply `service_credential.name` in the form `credentials/{name}`. +// Required on Create when using service-credential authentication; mutually +// exclusive with `aws_access_key`. The credential is referenced by name; its +// value is not carried here. On read, the resolved `id` and `is_deleted` are +// also populated. Only supported on AWS-hosted workspaces; Create requests from +// other clouds are rejected with INVALID_PARAMETER_VALUE. type ModelProviderServiceConfig_AmazonBedrockProviderDirectConfig_AuthMode_ServiceCredential struct { ServiceCredential ModelProviderServiceConfig_ServiceCredential `fieldmask:"service_credential"` } @@ -799,10 +771,6 @@ type modelProviderServiceConfig_AnthropicProviderDirectConfigAuthModeFieldMaskMe // is the signal that the provider service uses relayed auth; `plan_type` // further distinguishes which Anthropic subscription tier the token belongs to.. type ModelProviderServiceConfig_AnthropicProviderRelayedConfig struct { - // Which Anthropic subscription tier the relayed token belongs to. Optional; - // when unset the MPS gets the full governance surface (see TEAM_ENTERPRISE). - // Immutable after Create, so the tier cannot be flipped in place. - PlanType ModelProviderServiceConfig_AnthropicProviderRelayedConfig_AnthropicRelayedPlanType `fieldmask:"plan_type"` } // AWS access-key-pair auth for Amazon Bedrock: a SigV4-signing key pair.. @@ -848,12 +816,11 @@ type modelProviderServiceConfig_AzureOpenAiProviderConfigProviderModeFieldMaskMe // mutually-exclusive auth modes must be supplied on Create: - API key: set // `api_key`, leave `entra_service_principal` and `service_credential` unset. - // Entra ID (service principal): set `entra_service_principal`, leave `api_key` -// and `service_credential` unset. - UC service credential: set -// `service_credential.name` to the AIP-122 resource-name form -// `credentials/{name}`, leave `api_key` and `entra_service_principal` unset. -// The credential value lives in UC and is referenced by name, not held on this -// message. Only supported on Azure-hosted workspaces. Setting more than one -// mode is rejected.. +// and `service_credential` unset. - Unity Catalog service credential: set +// `service_credential.name` to the resource name `credentials/{name}`, leave +// `api_key` and `entra_service_principal` unset. The credential value lives in +// Unity Catalog and is referenced by name, not held on this message. Only +// supported on Azure-hosted workspaces. Setting more than one mode is rejected.. type ModelProviderServiceConfig_AzureOpenAiProviderDirectConfig struct { // Full Azure OpenAI endpoint base URL, e.g. // `https://myresource.openai.azure.com`. Required on Create. @@ -879,12 +846,12 @@ func (*ModelProviderServiceConfig_AzureOpenAiProviderDirectConfig_AuthMode_ApiKe } // ModelProviderServiceConfig_AzureOpenAiProviderDirectConfig_AuthMode_ServiceCredential selects ServiceCredential for ModelProviderServiceConfig_AzureOpenAiProviderDirectConfig.AuthMode. -// Reference to a UC service credential authorizing Azure OpenAI requests. On -// Create the caller supplies `service_credential.name` in the AIP-122 -// resource-name form `credentials/{name}`. Required on Create when using -// UC-service-credential auth; mutually exclusive with `api_key` and +// Reference to a Unity Catalog service credential authorizing Azure OpenAI +// requests. On Create, supply `service_credential.name` in the form +// `credentials/{name}`. Required on Create when using service-credential +// authentication; mutually exclusive with `api_key` and // `entra_service_principal`. The credential is referenced by name; its value is -// not carried here. On read the resolved `id` and `is_deleted` are also +// not carried here. On read, the resolved `id` and `is_deleted` are also // populated. Only supported on Azure-hosted workspaces; Create requests from // other clouds are rejected with INVALID_PARAMETER_VALUE. type ModelProviderServiceConfig_AzureOpenAiProviderDirectConfig_AuthMode_ServiceCredential struct { @@ -1040,8 +1007,8 @@ type modelProviderServiceConfig_GeminiEnterpriseProviderConfigProviderModeFieldM // // Authentication is one of two mutually exclusive modes; exactly one must be // supplied on Create: - API key: set `api_key`, leave `service_credential` -// unset. - UC service credential: set `service_credential`, leave `api_key` -// unset.. +// unset. - Unity Catalog service credential: set `service_credential`, leave +// `api_key` unset.. type ModelProviderServiceConfig_GeminiEnterpriseProviderDirectConfig struct { // Authentication mode. Exactly one variant may be set. AuthMode isModelProviderServiceConfig_GeminiEnterpriseProviderDirectConfig_AuthMode @@ -1074,10 +1041,11 @@ type modelProviderServiceConfig_GeminiEnterpriseProviderDirectConfigAuthModeFiel // Microsoft Foundry provider configuration.. type ModelProviderServiceConfig_MicrosoftFoundryProviderConfig struct { - // Direct (inline-credentials) form: caller supplies the Foundry endpoint URL + - // API key in the request body. Required on Create. Provider configuration mode. - // Exactly one variant may be set. (-- Wrapped in a oneof so future non-direct - // modes can be added as additional variants without a breaking change. --) + // Direct form: caller supplies the Foundry endpoint URL and authentication + // configuration in the request body. Required on Create. Provider configuration + // mode. Exactly one variant may be set. (-- Wrapped in a oneof so future + // non-direct modes can be added as additional variants without a breaking + // change. --) ProviderMode isModelProviderServiceConfig_MicrosoftFoundryProviderConfig_ProviderMode _ [0]modelProviderServiceConfig_MicrosoftFoundryProviderConfigProviderModeFieldMaskMetadata `fieldmask_oneof:"ProviderMode"` } @@ -1105,14 +1073,14 @@ type modelProviderServiceConfig_MicrosoftFoundryProviderConfigProviderModeFieldM // `entra_service_principal` and `service_credential` unset. - Entra ID (service // principal): set `entra_service_principal`, leave `api_key` and // `service_credential` unset. AI Gateway exchanges these for an Entra bearer -// token on outbound requests via the OAuth2 client-credentials grant. - UC -// service credential: set `service_credential.name` to the AIP-122 -// resource-name form `credentials/{name}`, leave `api_key` and -// `entra_service_principal` unset. The credential value lives in UC and is -// referenced by name, not held on this message. Only supported on Azure-hosted -// workspaces. Setting more than one mode is rejected.. +// token on outbound requests via the OAuth2 client-credentials grant. - Unity +// Catalog service credential: set `service_credential.name` to the resource +// name `credentials/{name}`, leave `api_key` and `entra_service_principal` +// unset. The credential value lives in Unity Catalog and is referenced by name, +// not held on this message. Only supported on Azure-hosted workspaces. Setting +// more than one mode is rejected.. type ModelProviderServiceConfig_MicrosoftFoundryProviderDirectConfig struct { - // Microsoft AI Foundry endpoint URL. Required on Create. + // Microsoft Foundry endpoint URL. Required on Create. BaseUrl *string `fieldmask:"base_url"` // Authentication mode. Exactly one variant may be set. AuthMode isModelProviderServiceConfig_MicrosoftFoundryProviderDirectConfig_AuthMode @@ -1124,7 +1092,7 @@ type isModelProviderServiceConfig_MicrosoftFoundryProviderDirectConfig_AuthMode } // ModelProviderServiceConfig_MicrosoftFoundryProviderDirectConfig_AuthMode_ApiKey selects ApiKey for ModelProviderServiceConfig_MicrosoftFoundryProviderDirectConfig.AuthMode. -// Microsoft AI Foundry API key. Mutually exclusive with the Entra and +// Microsoft Foundry API key. Mutually exclusive with the Entra and // service-credential modes. Supplied as inline plaintext via // `ProviderSecret.plaintext`. type ModelProviderServiceConfig_MicrosoftFoundryProviderDirectConfig_AuthMode_ApiKey struct { @@ -1135,12 +1103,12 @@ func (*ModelProviderServiceConfig_MicrosoftFoundryProviderDirectConfig_AuthMode_ } // ModelProviderServiceConfig_MicrosoftFoundryProviderDirectConfig_AuthMode_ServiceCredential selects ServiceCredential for ModelProviderServiceConfig_MicrosoftFoundryProviderDirectConfig.AuthMode. -// Reference to a UC service credential authorizing Microsoft Foundry requests. -// On Create the caller supplies `service_credential.name` in the AIP-122 -// resource-name form `credentials/{name}`. Required on Create when using -// UC-service-credential auth; mutually exclusive with `api_key` and +// Reference to a Unity Catalog service credential authorizing Microsoft Foundry +// requests. On Create, supply `service_credential.name` in the form +// `credentials/{name}`. Required on Create when using service-credential +// authentication; mutually exclusive with `api_key` and // `entra_service_principal`. The credential is referenced by name; its value is -// not carried here. On read the resolved `id` and `is_deleted` are also +// not carried here. On read, the resolved `id` and `is_deleted` are also // populated. Only supported on Azure-hosted workspaces; Create requests from // other clouds are rejected with INVALID_PARAMETER_VALUE. type ModelProviderServiceConfig_MicrosoftFoundryProviderDirectConfig_AuthMode_ServiceCredential struct { @@ -1168,16 +1136,14 @@ type modelProviderServiceConfig_MicrosoftFoundryProviderDirectConfigAuthModeFiel // Model target configuration for an external model destination.. type ModelProviderServiceConfig_ModelTargetConfig struct { - // Provider-side model identifier (e.g. "gpt-5", "claude-opus-4-7"). This is a - // string on the LLM provider's side, not a UC entity. The UC governance hook - // for external destinations is the ModelProviderService referenced by - // `ExternalModelConfig.model_provider_service`, not the model itself. + // Provider-side model identifier, such as `gpt-5` or `claude-opus-4-7`. This + // identifies a model at the upstream provider; it is not a Unity Catalog model + // resource. Model *string - // Provider-native API types the model supports (e.g. - // "openai/v1/chat/completions"). Used by the platform for request/response - // translation from the unified API type. At most 64 entries of at most 256 - // characters each; the list is persisted into the destination binding's bounded - // storage envelope. + // Provider-native API types supported by this model, such as + // `openai/v1/chat/completions`. AI Gateway uses these values to translate + // requests and responses. At most 64 entries of 256 characters each are + // allowed. NativeApiTypes []string } @@ -1247,9 +1213,9 @@ type modelProviderServiceConfig_OpenAiProviderDirectConfigAuthModeFieldMaskMetad // reads.. type ModelProviderServiceConfig_ProviderSecret struct { // How the credential value is supplied. Exactly one variant may be set. (-- - // Wrapped in a oneof so a future non-plaintext source (e.g. a Databricks secret - // reference `{{secrets//}}`, mirroring AIGW v2's ProviderSecret) - // can be added as an additional variant without a breaking change. --) + // Wrapped in a oneof so a non-plaintext source can be added as an additional + // variant without a breaking change; `secret_reference` is that variant, and + // further sources can follow the same way. --) Value isModelProviderServiceConfig_ProviderSecret_Value _ [0]modelProviderServiceConfig_ProviderSecretValueFieldMaskMetadata `fieldmask_oneof:"Value"` } @@ -1274,57 +1240,53 @@ type modelProviderServiceConfig_ProviderSecretValueFieldMaskMetadata struct { } // ---- Provider configuration (nested; see the `provider` oneof below) ---- The -// customer-owned UC service credential a ModelProviderService uses to -// authenticate to its provider, referenced by name.. +// customer-owned Unity Catalog service credential a ModelProviderService uses +// to authenticate to its provider, referenced by name.. type ModelProviderServiceConfig_ServiceCredential struct { - // Resource name of the bound UC service credential, in the AIP-122 form - // `credentials/{name}` (a metastore-level single-part credential name). On - // create the caller supplies the name here. On read it reflects the - // credential's current name at read time. + // Resource name of the bound Unity Catalog service credential, in the form + // `credentials/{name}`. On Create, supply the name here. On read, this field + // reflects the credential's current name. Name *string `fieldmask:"name"` } // A governed AI Gateway endpoint in Unity Catalog that routes inference -// requests to one or more model destinations (for example a foundation model or -// an external LLM reached through a ModelProviderService). Applies centralized -// access control, rate limits, guardrails, and auditing to the traffic it -// serves.. +// requests to one or more destinations, such as a foundation model +// or an external model reached through a model provider service. Applies +// centralized access control, rate limits, and auditing to its traffic.. type ModelService struct { // Resource name of the model service. Format: // `model-services/{catalog}.{schema}.{model_service}`. Each `{...}` component // is capped at 255 characters individually. Server-derived on Create from // `parent` + `model_service_id`; required and immutable on Update/Get/Delete. Name *string `fieldmask:"name"` - // The owner of the model service. Write-only; read owner via effective_owner. - Owner *string `fieldmask:"owner"` // The resolved owner of the ModelService. Falls back to the caller's identity // when `owner` is not explicitly set on creation. EffectiveOwner *string `fieldmask:"effective_owner"` // Metastore hosting the model service. MetastoreId *string `fieldmask:"metastore_id"` - // When the model service was created. + // Time the model service was created. CreateTime *types.Time `fieldmask:"create_time"` // Creator identity. CreatedBy *string `fieldmask:"created_by"` - // When the model service was last modified. + // Time the model service was last modified. UpdateTime *types.Time `fieldmask:"update_time"` // Identity of the last updater. UpdatedBy *string `fieldmask:"updated_by"` // User-provided description. Comment *string `fieldmask:"comment"` - // Operational configuration: destinations, routing, rate limits, inference - // table. Required on CreateModelService; on UpdateModelService it is required - // only when `config` (or a `config.*` subpath) appears in `update_mask`. + // Destinations, routing, rate limits, and payload logging configuration. + // Required on Create. On Update, provide this field when `update_mask` contains + // `config` or one of its subpaths. Config *ModelServiceConfig `fieldmask:"config"` - // Optimistic concurrency control token. Server-generated from the entity's - // state and returned on every read. To use it as an if-match precondition on a - // mutation, echo the last-read value back via the dedicated `etag` field on the - // Update / Delete request; the server rejects the mutation if the stored etag - // differs. + // Optimistic concurrency token returned on every read. To make an Update or + // Delete conditional, pass the last-read value in that request's `etag` field. + // In REST responses, this value is a base64 string; URL-encode it when setting + // the `etag` query parameter. Etag []byte `fieldmask:"etag"` - // Unified API types this endpoint supports (e.g. "chat", "embeddings", - // "completions"). Derived from the destinations' backing models / providers at - // read time. + // API types supported across this service's destinations, such as + // `openai/v1/chat/completions`, `openai/v1/embeddings`, and + // `mlflow/v1/chat/completions`. Derived from the backing models and providers + // at read time. SupportedApiTypes []string `fieldmask:"supported_api_types"` } @@ -1344,10 +1306,13 @@ type ModelServiceConfig struct { type ModelServiceConfig_DestinationConfig struct { // User-facing label for this destination, used in routing references. Name *string - // Backing-model category. Determines which oneof variant is populated. + // Backing-model category. Provide the matching type-specific configuration and + // leave the other type-specific configurations unset. DestinationType ModelServiceConfig_DestinationConfig_DestinationType - // Share of traffic sent to this destination, 0-100. Optional on fallback - // destinations; see FallbackConfig. + // Percentage of primary traffic sent to this destination, from 0 to 100. + // Required when there is more than one primary destination, in which case the + // primary percentages must sum to 100; a single primary destination receives + // all traffic. Fallback destinations are ordered and do not use this field. TrafficPercentage *int // Destination-type-specific configuration. TypeConfig isModelServiceConfig_DestinationConfig_TypeConfig @@ -1419,7 +1384,8 @@ type ModelServiceConfig_FallbackConfig struct { // the foundation model by its UC resource name; the platform resolves it to a // Model Serving endpoint at request time.. type ModelServiceConfig_PayPerTokenConfig struct { - // Resource name of the UC model. Format: `models/{catalog}.{schema}.{model}`. + // Resource name of the Unity Catalog model. Format: + // `models/{catalog}.{schema}.{model}`. Model *string } @@ -1429,10 +1395,11 @@ type ModelServiceConfig_PayPerTokenConfig struct { // Model Serving endpoint itself, not by this message.. type ModelServiceConfig_ProvisionedThroughputConfig struct { // Name of the backing Model Serving endpoint serving the provisioned- - // throughput foundation model, as the AIP-122 typed resource name - // `serving-endpoints/{name}`. The same UC model can be served on multiple Model - // Serving endpoints (different throughput / region / config); the caller picks - // which one this destination routes to. The endpoint must exist at create time. + // throughput foundation model, in the form `serving-endpoints/{name}`. The same + // Unity Catalog model can be served on multiple Model Serving endpoints with + // different throughput, regions, or configurations. The caller selects the + // endpoint to which this destination routes. The endpoint must exist at create + // time. ModelServingEndpoint *string // UC model FQN of the model served by the backing endpoint (e.g., // `system.ai.databricks-claude-opus-4-6`). Resolved from Model Serving at @@ -1444,52 +1411,27 @@ type ModelServiceConfig_ProvisionedThroughputConfig struct { // strategy, and fallback under a single sub-message.. type ModelServiceConfig_RoutingConfig struct { // Primary routing destinations. At most 10 are allowed. At least one is - // required on CreateModelService; on UpdateModelService it is required only - // when `config.routing` (or a `config.routing.*` subpath) appears in - // `update_mask`. + // required on Create. On Update, provide this list when replacing the full + // `config` or updating `config.routing.destinations`; other granular routing + // updates do not require resending destinations. The intermediate + // `config.routing` mask path is not supported. Destinations []ModelServiceConfig_DestinationConfig `fieldmask:"destinations"` - // Selects how requests are distributed across destinations. - RoutingStrategy isModelServiceConfig_RoutingConfig_RoutingStrategy - // Fallback routing config, applied after primary destinations fail. + // Fallback routing applied after a primary destination fails. Fallback + // destinations are tried in the listed order. Fallback *ModelServiceConfig_FallbackConfig `fieldmask:"fallback"` // Timeout for the first token of a streaming response. If a destination does // not return its first token within this duration, AI Gateway aborts the // attempt and fails over to the next destination. Applies to streaming requests // only. Leave unset for no first-token timeout. - FirstTokenTimeout *types.Duration `fieldmask:"first_token_timeout"` - _ [0]modelServiceConfig_RoutingConfigRoutingStrategyFieldMaskMetadata `fieldmask_oneof:"RoutingStrategy"` -} - -type isModelServiceConfig_RoutingConfig_RoutingStrategy interface { - isModelServiceConfig_RoutingConfig_RoutingStrategy() -} - -// ModelServiceConfig_RoutingConfig_RoutingStrategy_TrafficSplitting selects TrafficSplitting for ModelServiceConfig_RoutingConfig.RoutingStrategy. -// Marker message selecting request-based traffic splitting. Traffic is -// distributed according to each destination's traffic_percentage value; no -// configuration lives on this message itself. -type ModelServiceConfig_RoutingConfig_RoutingStrategy_TrafficSplitting struct { - TrafficSplitting ModelServiceConfig_RoutingConfig_TrafficSplitting `fieldmask:"traffic_splitting"` -} - -func (*ModelServiceConfig_RoutingConfig_RoutingStrategy_TrafficSplitting) isModelServiceConfig_RoutingConfig_RoutingStrategy() { -} - -type modelServiceConfig_RoutingConfigRoutingStrategyFieldMaskMetadata struct { - *ModelServiceConfig_RoutingConfig_RoutingStrategy_TrafficSplitting -} - -// Marker message selecting request-based traffic splitting across primary -// destinations. Split weights are read from each -// DestinationConfig.traffic_percentage.. -type ModelServiceConfig_RoutingConfig_TrafficSplitting struct { + FirstTokenTimeout *types.Duration `fieldmask:"first_token_timeout"` } // A rate limit applied to service requests. Leave `requests` or `tokens` unset // to impose no limit on that dimension; set a value to cap that dimension // within the renewal period.. type RateLimit struct { - // Scope key. Determines whether `principal` is required. + // Scope of the rate limit. Depending on this value, the limit applies to a + // principal, the service as a whole, each user by default, or a request tag. Key RateLimit_RateLimitKey // Renewal period. RenewalPeriod RateLimit_RateLimitRenewalPeriod @@ -1498,10 +1440,11 @@ type RateLimit struct { // `RATE_LIMIT_KEY_USER_DEFAULT`, or `RATE_LIMIT_KEY_REQUEST_TAG` (which must // not set a principal). Principal *string - // Max requests allowed within a renewal period. Leave unset for no request - // limit. + // Maximum requests allowed in one renewal period. Leave unset for no request + // limit. Set to `0` to deny all requests. Requests *int64 - // Max tokens allowed within a renewal period. Leave unset for no token limit. + // Maximum tokens allowed in one renewal period. Leave unset for no token limit. + // Set to `0` to deny all requests. Tokens *int64 // Request tag key this limit applies to. Required when `key` is // `RATE_LIMIT_KEY_REQUEST_TAG`, forbidden otherwise. @@ -1519,12 +1462,16 @@ type UpdateMcpServiceRequest struct { // (`mcp-services/{catalog}.{schema}.{mcp_service}`); only fields listed in // `update_mask` are applied. McpService *McpService - // The list of fields to update. The framework validates each path against the - // `mcp_service` field above. Wildcard paths (`paths: ["*"]`) are not supported; - // list each field path explicitly. + // Fields to update. Use `config` to replace the entire configuration. The + // replacement must include every required field; any optional field you omit is + // cleared. To preserve sibling fields, use one or more granular paths: + // `comment`, `config.source_connection.name`, `config.include_tool_selectors`, + // or `config.rate_limits`. Wildcard paths such as `*` are not supported. UpdateMask *types.FieldMask[McpService] - // If-match precondition: when set, the update proceeds only if the current - // server-side etag matches. Empty means an unconditional update. + // Optimistic concurrency token from the most recent read. When set, the update + // succeeds only if the resource has not changed. Leave unset for an + // unconditional update. For REST requests, URL-encode the base64 string + // returned by the API when setting the `etag` query parameter. Etag []byte } @@ -1536,12 +1483,19 @@ type UpdateModelProviderServiceRequest struct { // (`model-provider-services/{catalog}.{schema}.{model_provider_service}`); only // fields listed in `update_mask` are applied. ModelProviderService *ModelProviderService - // The list of fields to update. The framework validates each path against the - // `model_provider_service` field above. Wildcard paths (`paths: ["*"]`) are not - // supported; list each field path explicitly. + // Fields to update. Use `config` to replace the entire configuration. The + // replacement must include every required field; any optional field you omit is + // cleared. To preserve sibling fields, use one or more granular paths: + // `comment`, `config.provider`, `config.allow_all_targets`, `config.targets`, + // `config.forward_headers`, `config.forward_query_parameters`, + // `config.forward_unmanaged_paths`, `config.rate_limits`, or + // `config.inference_table`. The provider type is immutable, and wildcard paths + // such as `*` are not supported. UpdateMask *types.FieldMask[ModelProviderService] - // If-match precondition: when set, the update proceeds only if the current - // server-side etag matches. Empty means an unconditional update. + // Optimistic concurrency token from the most recent read. When set, the update + // succeeds only if the resource has not changed. Leave unset for an + // unconditional update. For REST requests, URL-encode the base64 string + // returned by the API when setting the `etag` query parameter. Etag []byte } @@ -1552,11 +1506,18 @@ type UpdateModelServiceRequest struct { // resource (`model-services/{catalog}.{schema}.{model_service}`); only fields // listed in `update_mask` are applied. ModelService *ModelService - // The list of fields to update. The framework validates each path against the - // `model_service` field above. Wildcard paths (`paths: ["*"]`) are not - // supported; list each field path explicitly. + // Fields to update. Use `config` to replace the entire configuration. The + // replacement must include every required field; any optional field you omit is + // cleared. To preserve sibling fields, use one or more granular paths: + // `comment`, `config.routing.destinations`, + // `config.routing.fallback.destinations`, `config.routing.first_token_timeout`, + // `config.rate_limits`, or `config.inference_table`. Intermediate paths such as + // `config.routing` and `config.routing.fallback`, and wildcard paths such as + // `*`, are not supported. UpdateMask *types.FieldMask[ModelService] - // If-match precondition: when set, the update proceeds only if the current - // server-side etag matches. Empty means an unconditional update. + // Optimistic concurrency token from the most recent read. When set, the update + // succeeds only if the resource has not changed. Leave unset for an + // unconditional update. For REST requests, URL-encode the base64 string + // returned by the API when setting the `etag` query parameter. Etag []byte } diff --git a/aigateway/v1/wire.go b/aigateway/v1/wire.go old mode 100755 new mode 100644 index d18cab0..8ea0c63 --- a/aigateway/v1/wire.go +++ b/aigateway/v1/wire.go @@ -3,11 +3,57 @@ package aigateway import ( + "bytes" + "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + func fieldMaskToWire[T any](mask *types.FieldMask[T]) *string { if mask == nil { return nil @@ -127,7 +173,6 @@ func deleteModelServiceRequestToWire(v *DeleteModelServiceRequest) (*deleteModel type inferenceTableConfigWire struct { Parent *string `json:"parent,omitempty"` TableNamePrefix *string `json:"table_name_prefix,omitempty"` - Disabled *bool `json:"disabled,omitempty"` Table *string `json:"table,omitempty"` IsDeleted *bool `json:"is_deleted,omitempty"` } @@ -139,7 +184,6 @@ func inferenceTableConfigToWire(v *InferenceTableConfig) (*inferenceTableConfigW return &inferenceTableConfigWire{ Parent: v.Parent, TableNamePrefix: v.TableNamePrefix, - Disabled: v.Disabled, Table: v.Table, IsDeleted: v.IsDeleted, }, nil @@ -152,7 +196,6 @@ func inferenceTableConfigFromWire(w *inferenceTableConfigWire) (*InferenceTableC return &InferenceTableConfig{ Parent: w.Parent, TableNamePrefix: w.TableNamePrefix, - Disabled: w.Disabled, Table: w.Table, IsDeleted: w.IsDeleted, }, nil @@ -274,7 +317,6 @@ func listModelServicesResponseFromWire(w *listModelServicesResponseWire) (*ListM type mcpServiceWire struct { Name *string `json:"name,omitempty"` - Owner *string `json:"owner,omitempty"` EffectiveOwner *string `json:"effective_owner,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` CreateTime *types.Time `json:"create_time,omitempty"` @@ -296,7 +338,6 @@ func mcpServiceToWire(v *McpService) (*mcpServiceWire, error) { } return &mcpServiceWire{ Name: v.Name, - Owner: v.Owner, EffectiveOwner: v.EffectiveOwner, MetastoreId: v.MetastoreId, CreateTime: v.CreateTime, @@ -319,7 +360,6 @@ func mcpServiceFromWire(w *mcpServiceWire) (*McpService, error) { } return &McpService{ Name: w.Name, - Owner: w.Owner, EffectiveOwner: w.EffectiveOwner, MetastoreId: w.MetastoreId, CreateTime: w.CreateTime, @@ -425,7 +465,6 @@ func mcpServiceConfig_SourceConnectionFromWire(w *mcpServiceConfig_SourceConnect type modelProviderServiceWire struct { Name *string `json:"name,omitempty"` - Owner *string `json:"owner,omitempty"` EffectiveOwner *string `json:"effective_owner,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` CreateTime *types.Time `json:"create_time,omitempty"` @@ -447,7 +486,6 @@ func modelProviderServiceToWire(v *ModelProviderService) (*modelProviderServiceW } return &modelProviderServiceWire{ Name: v.Name, - Owner: v.Owner, EffectiveOwner: v.EffectiveOwner, MetastoreId: v.MetastoreId, CreateTime: v.CreateTime, @@ -470,7 +508,6 @@ func modelProviderServiceFromWire(w *modelProviderServiceWire) (*ModelProviderSe } return &ModelProviderService{ Name: w.Name, - Owner: w.Owner, EffectiveOwner: w.EffectiveOwner, MetastoreId: w.MetastoreId, CreateTime: w.CreateTime, @@ -955,25 +992,20 @@ func modelProviderServiceConfig_AnthropicProviderDirectConfigFromWire(w *modelPr } type modelProviderServiceConfig_AnthropicProviderRelayedConfigWire struct { - PlanType ModelProviderServiceConfig_AnthropicProviderRelayedConfig_AnthropicRelayedPlanType `json:"plan_type,omitempty"` } func modelProviderServiceConfig_AnthropicProviderRelayedConfigToWire(v *ModelProviderServiceConfig_AnthropicProviderRelayedConfig) (*modelProviderServiceConfig_AnthropicProviderRelayedConfigWire, error) { if v == nil { return nil, nil } - return &modelProviderServiceConfig_AnthropicProviderRelayedConfigWire{ - PlanType: v.PlanType, - }, nil + return &modelProviderServiceConfig_AnthropicProviderRelayedConfigWire{}, nil } func modelProviderServiceConfig_AnthropicProviderRelayedConfigFromWire(w *modelProviderServiceConfig_AnthropicProviderRelayedConfigWire) (*ModelProviderServiceConfig_AnthropicProviderRelayedConfig, error) { if w == nil { return nil, nil } - return &ModelProviderServiceConfig_AnthropicProviderRelayedConfig{ - PlanType: w.PlanType, - }, nil + return &ModelProviderServiceConfig_AnthropicProviderRelayedConfig{}, nil } type modelProviderServiceConfig_AwsAccessKeyWire struct { @@ -1781,7 +1813,6 @@ func modelProviderServiceConfig_ServiceCredentialFromWire(w *modelProviderServic type modelServiceWire struct { Name *string `json:"name,omitempty"` - Owner *string `json:"owner,omitempty"` EffectiveOwner *string `json:"effective_owner,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` CreateTime *types.Time `json:"create_time,omitempty"` @@ -1804,7 +1835,6 @@ func modelServiceToWire(v *ModelService) (*modelServiceWire, error) { } return &modelServiceWire{ Name: v.Name, - Owner: v.Owner, EffectiveOwner: v.EffectiveOwner, MetastoreId: v.MetastoreId, CreateTime: v.CreateTime, @@ -1828,7 +1858,6 @@ func modelServiceFromWire(w *modelServiceWire) (*ModelService, error) { } return &ModelService{ Name: w.Name, - Owner: w.Owner, EffectiveOwner: w.EffectiveOwner, MetastoreId: w.MetastoreId, CreateTime: w.CreateTime, @@ -2109,10 +2138,9 @@ func modelServiceConfig_ProvisionedThroughputConfigFromWire(w *modelServiceConfi } type modelServiceConfig_RoutingConfigWire struct { - Destinations []modelServiceConfig_DestinationConfigWire `json:"destinations,omitempty"` - TrafficSplitting *modelServiceConfig_RoutingConfig_TrafficSplittingWire `json:"traffic_splitting,omitempty"` - Fallback *modelServiceConfig_FallbackConfigWire `json:"fallback,omitempty"` - FirstTokenTimeout *types.Duration `json:"first_token_timeout,omitempty"` + Destinations []modelServiceConfig_DestinationConfigWire `json:"destinations,omitempty"` + Fallback *modelServiceConfig_FallbackConfigWire `json:"fallback,omitempty"` + FirstTokenTimeout *types.Duration `json:"first_token_timeout,omitempty"` } func modelServiceConfig_RoutingConfigToWire(v *ModelServiceConfig_RoutingConfig) (*modelServiceConfig_RoutingConfigWire, error) { @@ -2127,23 +2155,8 @@ func modelServiceConfig_RoutingConfigToWire(v *ModelServiceConfig_RoutingConfig) if err != nil { return nil, fmt.Errorf("%s: %w", "ModelServiceConfig_RoutingConfig.Fallback", err) } - var routingStrategyTrafficSplittingWire *modelServiceConfig_RoutingConfig_TrafficSplittingWire - switch value := v.RoutingStrategy.(type) { - case nil: - case *ModelServiceConfig_RoutingConfig_RoutingStrategy_TrafficSplitting: - if value != nil { - routingStrategyTrafficSplittingConverted, err := modelServiceConfig_RoutingConfig_TrafficSplittingToWire(&value.TrafficSplitting) - if err != nil { - return nil, fmt.Errorf("%s: %w", "ModelServiceConfig_RoutingConfig.RoutingStrategy.TrafficSplitting", err) - } - routingStrategyTrafficSplittingWire = routingStrategyTrafficSplittingConverted - } - default: - return nil, fmt.Errorf("%s: unsupported oneof implementation %T", "ModelServiceConfig_RoutingConfig.RoutingStrategy", value) - } return &modelServiceConfig_RoutingConfigWire{ Destinations: destinationsWireValue, - TrafficSplitting: routingStrategyTrafficSplittingWire, Fallback: fallbackWireValue, FirstTokenTimeout: v.FirstTokenTimeout, }, nil @@ -2153,13 +2166,6 @@ func modelServiceConfig_RoutingConfigFromWire(w *modelServiceConfig_RoutingConfi if w == nil { return nil, nil } - routingStrategyMembers := 0 - if w.TrafficSplitting != nil { - routingStrategyMembers++ - } - if routingStrategyMembers > 1 { - return nil, fmt.Errorf("%s: multiple oneof members set", "ModelServiceConfig_RoutingConfig.RoutingStrategy") - } destinationsPublicValue, err := convertSlice(w.Destinations, modelServiceConfig_DestinationConfigFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "ModelServiceConfig_RoutingConfig.Destinations", err) @@ -2168,46 +2174,19 @@ func modelServiceConfig_RoutingConfigFromWire(w *modelServiceConfig_RoutingConfi if err != nil { return nil, fmt.Errorf("%s: %w", "ModelServiceConfig_RoutingConfig.Fallback", err) } - var routingStrategySelection isModelServiceConfig_RoutingConfig_RoutingStrategy - switch { - case w.TrafficSplitting != nil: - routingStrategyTrafficSplittingConverted, err := modelServiceConfig_RoutingConfig_TrafficSplittingFromWire(w.TrafficSplitting) - if err != nil { - return nil, fmt.Errorf("%s: %w", "ModelServiceConfig_RoutingConfig.RoutingStrategy.TrafficSplitting", err) - } - routingStrategySelection = &ModelServiceConfig_RoutingConfig_RoutingStrategy_TrafficSplitting{TrafficSplitting: *routingStrategyTrafficSplittingConverted} - } return &ModelServiceConfig_RoutingConfig{ Destinations: destinationsPublicValue, Fallback: fallbackPublicValue, FirstTokenTimeout: w.FirstTokenTimeout, - RoutingStrategy: routingStrategySelection, }, nil } -type modelServiceConfig_RoutingConfig_TrafficSplittingWire struct { -} - -func modelServiceConfig_RoutingConfig_TrafficSplittingToWire(v *ModelServiceConfig_RoutingConfig_TrafficSplitting) (*modelServiceConfig_RoutingConfig_TrafficSplittingWire, error) { - if v == nil { - return nil, nil - } - return &modelServiceConfig_RoutingConfig_TrafficSplittingWire{}, nil -} - -func modelServiceConfig_RoutingConfig_TrafficSplittingFromWire(w *modelServiceConfig_RoutingConfig_TrafficSplittingWire) (*ModelServiceConfig_RoutingConfig_TrafficSplitting, error) { - if w == nil { - return nil, nil - } - return &ModelServiceConfig_RoutingConfig_TrafficSplitting{}, nil -} - type rateLimitWire struct { Key RateLimit_RateLimitKey `json:"key,omitempty"` RenewalPeriod RateLimit_RateLimitRenewalPeriod `json:"renewal_period,omitempty"` Principal *string `json:"principal,omitempty"` - Requests *int64 `json:"requests,omitempty"` - Tokens *int64 `json:"tokens,omitempty"` + Requests *wireInt64 `json:"requests,omitempty"` + Tokens *wireInt64 `json:"tokens,omitempty"` RequestTagKey *string `json:"request_tag_key,omitempty"` RequestTagValue *string `json:"request_tag_value,omitempty"` } @@ -2216,12 +2195,20 @@ func rateLimitToWire(v *RateLimit) (*rateLimitWire, error) { if v == nil { return nil, nil } + requestsWireValue, err := int64ToWire(v.Requests) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RateLimit.Requests", err) + } + tokensWireValue, err := int64ToWire(v.Tokens) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RateLimit.Tokens", err) + } return &rateLimitWire{ Key: v.Key, RenewalPeriod: v.RenewalPeriod, Principal: v.Principal, - Requests: v.Requests, - Tokens: v.Tokens, + Requests: requestsWireValue, + Tokens: tokensWireValue, RequestTagKey: v.RequestTagKey, RequestTagValue: v.RequestTagValue, }, nil @@ -2231,12 +2218,20 @@ func rateLimitFromWire(w *rateLimitWire) (*RateLimit, error) { if w == nil { return nil, nil } + requestsPublicValue, err := int64FromWire(w.Requests) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RateLimit.Requests", err) + } + tokensPublicValue, err := int64FromWire(w.Tokens) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RateLimit.Tokens", err) + } return &RateLimit{ Key: w.Key, RenewalPeriod: w.RenewalPeriod, Principal: w.Principal, - Requests: w.Requests, - Tokens: w.Tokens, + Requests: requestsPublicValue, + Tokens: tokensPublicValue, RequestTagKey: w.RequestTagKey, RequestTagValue: w.RequestTagValue, }, nil diff --git a/alerts/CHANGELOG.md b/alerts/CHANGELOG.md index 6224c04..19f237c 100644 --- a/alerts/CHANGELOG.md +++ b/alerts/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/alerts/go.mod b/alerts/go.mod index 27c5afe..e89e7e2 100644 --- a/alerts/go.mod +++ b/alerts/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/alerts/internal/version.go b/alerts/internal/version.go index 52ae2e5..31d87e4 100644 --- a/alerts/internal/version.go +++ b/alerts/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-alerts" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/alerts/v1/client.go b/alerts/v1/client.go old mode 100755 new mode 100644 index e66367e..481bdd0 --- a/alerts/v1/client.go +++ b/alerts/v1/client.go @@ -75,8 +75,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Creates an alert. -func (c *internalClient) CreateAlert(ctx context.Context, req *CreateAlertRequest, opts ...call.Option) (*Alert, error) { - wireReq, err := createAlertRequestToWire(req) +func (c *internalClient) CreateAlert(ctx context.Context, req CreateAlertRequest, opts ...call.Option) (*Alert, error) { + wireReq, err := createAlertRequestToWire(&req) if err != nil { return nil, err } @@ -141,7 +141,7 @@ func (c *internalClient) CreateAlert(ctx context.Context, req *CreateAlertReques } // Gets an alert. -func (c *internalClient) GetAlert(ctx context.Context, req *GetAlertRequest, opts ...call.Option) (*Alert, error) { +func (c *internalClient) GetAlert(ctx context.Context, req GetAlertRequest, opts ...call.Option) (*Alert, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -155,7 +155,11 @@ func (c *internalClient) GetAlert(ctx context.Context, req *GetAlertRequest, opt } pb := pathBuilder{} pb.literal("/api/2.0/sql/alerts/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -203,8 +207,8 @@ func (c *internalClient) GetAlert(ctx context.Context, req *GetAlertRequest, opt // Gets a list of alerts accessible to the user, ordered by creation time. // **Warning:** Calling this API concurrently 10 or more times could result in // throttling, service degradation, or a temporary ban. -func (c *internalClient) ListAlerts(ctx context.Context, req *ListAlertsRequest, opts ...call.Option) (*ListAlertsResponse, error) { - wireReq, err := listAlertsRequestToWire(req) +func (c *internalClient) ListAlerts(ctx context.Context, req ListAlertsRequest, opts ...call.Option) (*ListAlertsResponse, error) { + wireReq, err := listAlertsRequestToWire(&req) if err != nil { return nil, err } @@ -274,7 +278,7 @@ func (c *internalClient) ListAlerts(ctx context.Context, req *ListAlertsRequest, // // For example: // -// for item, err := range c.ListAlertsIter(ctx, &ListAlertsRequest{}) { +// for item, err := range c.ListAlertsIter(ctx, ListAlertsRequest{}) { // if err != nil { // return err // } @@ -286,16 +290,13 @@ func (c *internalClient) ListAlerts(ctx context.Context, req *ListAlertsRequest, // // Callers who need custom pagination logic should use // ListAlerts directly. -func (c *internalClient) ListAlertsIter(ctx context.Context, req *ListAlertsRequest, opts ...call.Option) iter.Seq2[*ListAlertsResponseAlert, error] { +func (c *internalClient) ListAlertsIter(ctx context.Context, req ListAlertsRequest, opts ...call.Option) iter.Seq2[*ListAlertsResponseAlert, error] { return func(yield func(*ListAlertsResponseAlert, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListAlertsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListAlerts(ctx, &pageReq, opts...) + resp, err := c.ListAlerts(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -316,7 +317,7 @@ func (c *internalClient) ListAlertsIter(ctx context.Context, req *ListAlertsRequ // Moves an alert to the trash. Trashed alerts immediately disappear from // searches and list views, and can no longer trigger. You can restore a trashed // alert through the UI. A trashed alert is permanently deleted after 30 days. -func (c *internalClient) TrashAlert(ctx context.Context, req *TrashAlertRequest, opts ...call.Option) (*Empty, error) { +func (c *internalClient) TrashAlert(ctx context.Context, req TrashAlertRequest, opts ...call.Option) (*Empty, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -330,7 +331,11 @@ func (c *internalClient) TrashAlert(ctx context.Context, req *TrashAlertRequest, } pb := pathBuilder{} pb.literal("/api/2.0/sql/alerts/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -370,8 +375,8 @@ func (c *internalClient) TrashAlert(ctx context.Context, req *TrashAlertRequest, } // Updates an alert. -func (c *internalClient) UpdateAlert(ctx context.Context, req *UpdateAlertRequest, opts ...call.Option) (*Alert, error) { - wireReq, err := updateAlertRequestToWire(req) +func (c *internalClient) UpdateAlert(ctx context.Context, req UpdateAlertRequest, opts ...call.Option) (*Alert, error) { + wireReq, err := updateAlertRequestToWire(&req) if err != nil { return nil, err } @@ -392,7 +397,11 @@ func (c *internalClient) UpdateAlert(ctx context.Context, req *UpdateAlertReques } pb := pathBuilder{} pb.literal("/api/2.0/sql/alerts/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/alerts/v1/genhelper.go b/alerts/v1/genhelper.go old mode 100755 new mode 100644 index b39ebc3..7ddaf96 --- a/alerts/v1/genhelper.go +++ b/alerts/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/alerts/v2/client.go b/alerts/v2/client.go old mode 100755 new mode 100644 index 14f9d32..00b54f7 --- a/alerts/v2/client.go +++ b/alerts/v2/client.go @@ -75,8 +75,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Create Alert -func (c *internalClient) CreateAlert(ctx context.Context, req *CreateAlertRequest, opts ...call.Option) (*Alert, error) { - wireReq, err := createAlertRequestToWire(req) +func (c *internalClient) CreateAlert(ctx context.Context, req CreateAlertRequest, opts ...call.Option) (*Alert, error) { + wireReq, err := createAlertRequestToWire(&req) if err != nil { return nil, err } @@ -141,7 +141,7 @@ func (c *internalClient) CreateAlert(ctx context.Context, req *CreateAlertReques } // Gets an alert. -func (c *internalClient) GetAlert(ctx context.Context, req *GetAlertRequest, opts ...call.Option) (*Alert, error) { +func (c *internalClient) GetAlert(ctx context.Context, req GetAlertRequest, opts ...call.Option) (*Alert, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -155,7 +155,11 @@ func (c *internalClient) GetAlert(ctx context.Context, req *GetAlertRequest, opt } pb := pathBuilder{} pb.literal("/api/2.0/alerts/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -201,8 +205,8 @@ func (c *internalClient) GetAlert(ctx context.Context, req *GetAlertRequest, opt } // Gets a list of alerts accessible to the user, ordered by creation time. -func (c *internalClient) ListAlerts(ctx context.Context, req *ListAlertsRequest, opts ...call.Option) (*ListAlertsResponse, error) { - wireReq, err := listAlertsRequestToWire(req) +func (c *internalClient) ListAlerts(ctx context.Context, req ListAlertsRequest, opts ...call.Option) (*ListAlertsResponse, error) { + wireReq, err := listAlertsRequestToWire(&req) if err != nil { return nil, err } @@ -272,7 +276,7 @@ func (c *internalClient) ListAlerts(ctx context.Context, req *ListAlertsRequest, // // For example: // -// for item, err := range c.ListAlertsIter(ctx, &ListAlertsRequest{}) { +// for item, err := range c.ListAlertsIter(ctx, ListAlertsRequest{}) { // if err != nil { // return err // } @@ -284,16 +288,13 @@ func (c *internalClient) ListAlerts(ctx context.Context, req *ListAlertsRequest, // // Callers who need custom pagination logic should use // ListAlerts directly. -func (c *internalClient) ListAlertsIter(ctx context.Context, req *ListAlertsRequest, opts ...call.Option) iter.Seq2[*Alert, error] { +func (c *internalClient) ListAlertsIter(ctx context.Context, req ListAlertsRequest, opts ...call.Option) iter.Seq2[*Alert, error] { return func(yield func(*Alert, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListAlertsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListAlerts(ctx, &pageReq, opts...) + resp, err := c.ListAlerts(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -314,8 +315,8 @@ func (c *internalClient) ListAlertsIter(ctx context.Context, req *ListAlertsRequ // Moves an alert to the trash. Trashed alerts immediately disappear from list // views, and can no longer trigger. You can restore a trashed alert through the // UI. A trashed alert is permanently deleted after 30 days. -func (c *internalClient) TrashAlert(ctx context.Context, req *TrashAlertRequest, opts ...call.Option) (*Empty, error) { - wireReq, err := trashAlertRequestToWire(req) +func (c *internalClient) TrashAlert(ctx context.Context, req TrashAlertRequest, opts ...call.Option) (*Empty, error) { + wireReq, err := trashAlertRequestToWire(&req) if err != nil { return nil, err } @@ -332,7 +333,11 @@ func (c *internalClient) TrashAlert(ctx context.Context, req *TrashAlertRequest, } pb := pathBuilder{} pb.literal("/api/2.0/alerts/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "purge", wireReq.Purge); err != nil { @@ -375,8 +380,8 @@ func (c *internalClient) TrashAlert(ctx context.Context, req *TrashAlertRequest, } // Update alert -func (c *internalClient) UpdateAlert(ctx context.Context, req *UpdateAlertRequest, opts ...call.Option) (*Alert, error) { - wireReq, err := updateAlertRequestToWire(req) +func (c *internalClient) UpdateAlert(ctx context.Context, req UpdateAlertRequest, opts ...call.Option) (*Alert, error) { + wireReq, err := updateAlertRequestToWire(&req) if err != nil { return nil, err } @@ -397,7 +402,11 @@ func (c *internalClient) UpdateAlert(ctx context.Context, req *UpdateAlertReques } pb := pathBuilder{} pb.literal("/api/2.0/alerts/") - pb.singleSegment(*req.Alert.Id) + if req.Alert == nil || req.Alert.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Alert.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { diff --git a/alerts/v2/genhelper.go b/alerts/v2/genhelper.go old mode 100755 new mode 100644 index b39ebc3..7ddaf96 --- a/alerts/v2/genhelper.go +++ b/alerts/v2/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/alerts/v2/model.go b/alerts/v2/model.go old mode 100755 new mode 100644 index 5f03318..aaa6552 --- a/alerts/v2/model.go +++ b/alerts/v2/model.go @@ -65,7 +65,7 @@ const ( ) type Alert struct { - // UUID identifying the alert. + // The canonical identifier of the alert to retrieve information about. Id *string `fieldmask:"id"` // The display name of the alert. DisplayName *string `fieldmask:"display_name"` @@ -109,8 +109,22 @@ type Alert struct { // output-only field that shows the resolved run-as identity after applying // permissions and defaults. EffectiveRunAs *AlertRunAs `fieldmask:"effective_run_as"` - // Query parameters bound when executing the alert query, referenced in the - // query text with `:name` syntax. Static values only. + // A list of parameters to pass into the alert SQL query statement containing + // parameter markers. Static values only. + // + // Reference a parameter in the query text as `:name`. Each parameter must have + // a unique, non-empty name. Each parameter consists of a name, a value, and + // optionally a type. To represent a NULL value, the `value` field may be + // omitted or set to `null` explicitly. If the `type` field is omitted, the + // value is interpreted as a string. + // + // If the type is given, parameters will be checked for type correctness + // according to the given type. A value is correct if the provided string can be + // converted to the requested type using the `cast` function. The exact + // semantics are described in the section [`cast` function] of the SQL language + // reference. + // + // [`cast` function]: https://docs.databricks.com/sql/language-manual/functions/cast.html Parameters []AlertStatementParameter `fieldmask:"parameters"` } @@ -252,21 +266,20 @@ type alertRunAsIdentityFieldMaskMetadata struct { *AlertRunAs_Identity_ServicePrincipalName } -// Redash-owned copy of the internal StatementParameter for the external AlertV2 -// API. The internal `ordinal` and `args` fields are intentionally omitted: the -// public API supports only flat, named scalar parameters; complex types (ARRAY, -// MAP, STRUCT) are not supported. This mirrors SEA's public StatementParameter -// schema, see: cmdexec/sql-exec-api/proto/sql_exec_api_service.proto:763-779. +// A named parameter bound to the alert query. Only flat, named scalar +// parameters are supported; complex types such as ARRAY, MAP, and STRUCT are +// not.. type AlertStatementParameter struct { - // The name of the parameter, referenced in the query as `:name`. + // The name of the parameter. Reference it in the query text as `:name`. + // Required, must be non-empty, and must be unique across the alert's + // parameters. Name *string - // The bound value for the parameter, given as a string. If omitted, the value - // is interpreted as NULL. + // The value bound to the parameter, represented as a string. If omitted, the + // value is interpreted as NULL. Value *string - // The SQL data type of the parameter, e.g. STRING, INT, or DATE. Defaults to - // STRING. This is a string rather than an enum because scalar subtypes such as - // DECIMAL(10, 4) cannot be enumerated. Complex types such as ARRAY, MAP, and - // STRUCT are not supported. + // The SQL data type of the parameter, for example `STRING`, `INT`, or + // `DECIMAL(10, 2)`. If no type is given the type is assumed to be `STRING`. + // Complex types such as `ARRAY`, `MAP`, and `STRUCT` are not supported. Type *string } diff --git a/apps/CHANGELOG.md b/apps/CHANGELOG.md index 6224c04..19f237c 100644 --- a/apps/CHANGELOG.md +++ b/apps/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/apps/go.mod b/apps/go.mod index bef3476..46436e5 100644 --- a/apps/go.mod +++ b/apps/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/apps/internal/version.go b/apps/internal/version.go index 743ccf9..b577aa9 100644 --- a/apps/internal/version.go +++ b/apps/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-apps" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/apps/v1/client.go b/apps/v1/client.go old mode 100755 new mode 100644 index b4b124b..488d1fd --- a/apps/v1/client.go +++ b/apps/v1/client.go @@ -79,8 +79,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Creates an app update and starts the update process. The update process is // asynchronous and the status of the update can be checked with the // GetAppUpdate method. -func (c *internalClient) asyncUpdateAppBase(ctx context.Context, req *AsyncUpdateAppRequest, opts ...call.Option) (*AppUpdate, error) { - wireReq, err := asyncUpdateAppRequestToWire(req) +func (c *internalClient) asyncUpdateAppBase(ctx context.Context, req AsyncUpdateAppRequest, opts ...call.Option) (*AppUpdate, error) { + wireReq, err := asyncUpdateAppRequestToWire(&req) if err != nil { return nil, err } @@ -101,7 +101,11 @@ func (c *internalClient) asyncUpdateAppBase(ctx context.Context, req *AsyncUpdat } pb := pathBuilder{} pb.literal("/api/2.0/apps/") - pb.singleSegment(*req.AppName) + if req.AppName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.AppName) + } pb.literal("/update") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -151,7 +155,7 @@ func (c *internalClient) asyncUpdateAppBase(ctx context.Context, req *AsyncUpdat // Creates an app update and starts the update process. The update process is // asynchronous and the status of the update can be checked with the // GetAppUpdate method. -func (c *internalClient) AsyncUpdateApp(ctx context.Context, req *AsyncUpdateAppRequest, opts ...call.Option) (*AsyncUpdateAppWaiter, error) { +func (c *internalClient) AsyncUpdateApp(ctx context.Context, req AsyncUpdateAppRequest, opts ...call.Option) (*AsyncUpdateAppWaiter, error) { if req.AppName == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "AppName") } @@ -168,13 +172,18 @@ func (c *internalClient) AsyncUpdateApp(ctx context.Context, req *AsyncUpdateApp // AsyncUpdateAppWaiter tracks the state of the operation started by AsyncUpdateApp. type AsyncUpdateAppWaiter struct { - poll func(context.Context, *GetAppUpdateRequest, ...call.Option) (*AppUpdate, error) + poll func(context.Context, GetAppUpdateRequest, ...call.Option) (*AppUpdate, error) appName string } +// GetAppName returns the AppName value used to identify the operation. +func (w *AsyncUpdateAppWaiter) GetAppName() string { + return w.appName +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *AsyncUpdateAppWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetAppUpdateRequest{ + pollResp, err := w.poll(ctx, GetAppUpdateRequest{ AppName: &w.appName, }, opts...) if err != nil { @@ -202,7 +211,7 @@ func (w *AsyncUpdateAppWaiter) Done(ctx context.Context, opts ...call.Option) (b func (w *AsyncUpdateAppWaiter) Wait(ctx context.Context, opts ...lro.Option) (*AppUpdate, error) { var result *AppUpdate poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetAppUpdateRequest{ + pollResp, err := w.poll(ctx, GetAppUpdateRequest{ AppName: &w.appName, }) if err != nil { @@ -239,8 +248,8 @@ func (w *AsyncUpdateAppWaiter) Wait(ctx context.Context, opts ...lro.Option) (*A } // Creates a new app. -func (c *internalClient) createAppBase(ctx context.Context, req *CreateAppRequest, opts ...call.Option) (*App, error) { - wireReq, err := createAppRequestToWire(req) +func (c *internalClient) createAppBase(ctx context.Context, req CreateAppRequest, opts ...call.Option) (*App, error) { + wireReq, err := createAppRequestToWire(&req) if err != nil { return nil, err } @@ -308,7 +317,7 @@ func (c *internalClient) createAppBase(ctx context.Context, req *CreateAppReques } // Creates a new app. -func (c *internalClient) CreateApp(ctx context.Context, req *CreateAppRequest, opts ...call.Option) (*CreateAppWaiter, error) { +func (c *internalClient) CreateApp(ctx context.Context, req CreateAppRequest, opts ...call.Option) (*CreateAppWaiter, error) { resp, err := c.createAppBase(ctx, req, opts...) if err != nil { return nil, err @@ -324,13 +333,18 @@ func (c *internalClient) CreateApp(ctx context.Context, req *CreateAppRequest, o // CreateAppWaiter tracks the state of the operation started by CreateApp. type CreateAppWaiter struct { - poll func(context.Context, *GetAppRequest, ...call.Option) (*App, error) + poll func(context.Context, GetAppRequest, ...call.Option) (*App, error) name string } +// GetName returns the Name value used to identify the operation. +func (w *CreateAppWaiter) GetName() string { + return w.name +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *CreateAppWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetAppRequest{ + pollResp, err := w.poll(ctx, GetAppRequest{ Name: &w.name, }, opts...) if err != nil { @@ -358,7 +372,7 @@ func (w *CreateAppWaiter) Done(ctx context.Context, opts ...call.Option) (bool, func (w *CreateAppWaiter) Wait(ctx context.Context, opts ...lro.Option) (*App, error) { var result *App poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetAppRequest{ + pollResp, err := w.poll(ctx, GetAppRequest{ Name: &w.name, }) if err != nil { @@ -395,8 +409,8 @@ func (w *CreateAppWaiter) Wait(ctx context.Context, opts ...lro.Option) (*App, e } // Creates an app deployment for the app with the supplied name. -func (c *internalClient) createAppDeploymentBase(ctx context.Context, req *CreateAppDeploymentRequest, opts ...call.Option) (*AppDeployment, error) { - wireReq, err := createAppDeploymentRequestToWire(req) +func (c *internalClient) createAppDeploymentBase(ctx context.Context, req CreateAppDeploymentRequest, opts ...call.Option) (*AppDeployment, error) { + wireReq, err := createAppDeploymentRequestToWire(&req) if err != nil { return nil, err } @@ -417,7 +431,11 @@ func (c *internalClient) createAppDeploymentBase(ctx context.Context, req *Creat } pb := pathBuilder{} pb.literal("/api/2.0/apps/") - pb.singleSegment(*req.AppName) + if req.AppName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.AppName) + } pb.literal("/deployments") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -465,7 +483,7 @@ func (c *internalClient) createAppDeploymentBase(ctx context.Context, req *Creat } // Creates an app deployment for the app with the supplied name. -func (c *internalClient) CreateAppDeployment(ctx context.Context, req *CreateAppDeploymentRequest, opts ...call.Option) (*CreateAppDeploymentWaiter, error) { +func (c *internalClient) CreateAppDeployment(ctx context.Context, req CreateAppDeploymentRequest, opts ...call.Option) (*CreateAppDeploymentWaiter, error) { if req.AppName == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "AppName") } @@ -486,14 +504,24 @@ func (c *internalClient) CreateAppDeployment(ctx context.Context, req *CreateApp // CreateAppDeploymentWaiter tracks the state of the operation started by CreateAppDeployment. type CreateAppDeploymentWaiter struct { - poll func(context.Context, *GetAppDeploymentRequest, ...call.Option) (*AppDeployment, error) + poll func(context.Context, GetAppDeploymentRequest, ...call.Option) (*AppDeployment, error) deploymentId string appName string } +// GetDeploymentId returns the DeploymentId value used to identify the operation. +func (w *CreateAppDeploymentWaiter) GetDeploymentId() string { + return w.deploymentId +} + +// GetAppName returns the AppName value used to identify the operation. +func (w *CreateAppDeploymentWaiter) GetAppName() string { + return w.appName +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *CreateAppDeploymentWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetAppDeploymentRequest{ + pollResp, err := w.poll(ctx, GetAppDeploymentRequest{ DeploymentId: &w.deploymentId, AppName: &w.appName, }, opts...) @@ -522,7 +550,7 @@ func (w *CreateAppDeploymentWaiter) Done(ctx context.Context, opts ...call.Optio func (w *CreateAppDeploymentWaiter) Wait(ctx context.Context, opts ...lro.Option) (*AppDeployment, error) { var result *AppDeployment poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetAppDeploymentRequest{ + pollResp, err := w.poll(ctx, GetAppDeploymentRequest{ DeploymentId: &w.deploymentId, AppName: &w.appName, }) @@ -560,8 +588,8 @@ func (w *CreateAppDeploymentWaiter) Wait(ctx context.Context, opts ...lro.Option } // Creates a custom template. -func (c *internalClient) CreateCustomTemplate(ctx context.Context, req *CreateCustomTemplateRequest, opts ...call.Option) (*CustomTemplate, error) { - wireReq, err := createCustomTemplateRequestToWire(req) +func (c *internalClient) CreateCustomTemplate(ctx context.Context, req CreateCustomTemplateRequest, opts ...call.Option) (*CustomTemplate, error) { + wireReq, err := createCustomTemplateRequestToWire(&req) if err != nil { return nil, err } @@ -626,8 +654,8 @@ func (c *internalClient) CreateCustomTemplate(ctx context.Context, req *CreateCu } // Creates a new app space. -func (c *internalClient) createSpaceBase(ctx context.Context, req *CreateSpaceRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := createSpaceRequestToWire(req) +func (c *internalClient) createSpaceBase(ctx context.Context, req CreateSpaceRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := createSpaceRequestToWire(&req) if err != nil { return nil, err } @@ -692,7 +720,7 @@ func (c *internalClient) createSpaceBase(ctx context.Context, req *CreateSpaceRe } // Creates a new app space. -func (c *internalClient) CreateSpace(ctx context.Context, req *CreateSpaceRequest, opts ...call.Option) (*CreateSpaceOperation, error) { +func (c *internalClient) CreateSpace(ctx context.Context, req CreateSpaceRequest, opts ...call.Option) (*CreateSpaceOperation, error) { operation, err := c.createSpaceBase(ctx, req, opts...) if err != nil { return nil, err @@ -709,7 +737,7 @@ func (c *internalClient) CreateSpace(ctx context.Context, req *CreateSpaceReques // CreateSpaceOperation tracks the state of the long-running operation started by CreateSpace. type CreateSpaceOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -735,7 +763,7 @@ func (o *CreateSpaceOperation) Metadata() (*Space, error) { // Done refreshes the operation and reports whether it has completed. func (o *CreateSpaceOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -753,7 +781,7 @@ func (o *CreateSpaceOperation) Done(ctx context.Context, opts ...call.Option) (b func (o *CreateSpaceOperation) Wait(ctx context.Context, opts ...lro.Option) (*Space, error) { var result *Space poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -791,7 +819,7 @@ func (o *CreateSpaceOperation) Wait(ctx context.Context, opts ...lro.Option) (*S } // Deletes an app. -func (c *internalClient) DeleteApp(ctx context.Context, req *DeleteAppRequest, opts ...call.Option) (*App, error) { +func (c *internalClient) DeleteApp(ctx context.Context, req DeleteAppRequest, opts ...call.Option) (*App, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -805,7 +833,11 @@ func (c *internalClient) DeleteApp(ctx context.Context, req *DeleteAppRequest, o } pb := pathBuilder{} pb.literal("/api/2.0/apps/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -851,7 +883,7 @@ func (c *internalClient) DeleteApp(ctx context.Context, req *DeleteAppRequest, o } // Deletes the thumbnail for an app. -func (c *internalClient) DeleteAppThumbnail(ctx context.Context, req *DeleteAppThumbnailRequest, opts ...call.Option) error { +func (c *internalClient) DeleteAppThumbnail(ctx context.Context, req DeleteAppThumbnailRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -865,7 +897,11 @@ func (c *internalClient) DeleteAppThumbnail(ctx context.Context, req *DeleteAppT } pb := pathBuilder{} pb.literal("/api/2.0/apps/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/thumbnail") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -903,7 +939,7 @@ func (c *internalClient) DeleteAppThumbnail(ctx context.Context, req *DeleteAppT } // Deletes the custom template with the specified name. -func (c *internalClient) DeleteCustomTemplate(ctx context.Context, req *DeleteCustomTemplateRequest, opts ...call.Option) (*CustomTemplate, error) { +func (c *internalClient) DeleteCustomTemplate(ctx context.Context, req DeleteCustomTemplateRequest, opts ...call.Option) (*CustomTemplate, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -917,7 +953,11 @@ func (c *internalClient) DeleteCustomTemplate(ctx context.Context, req *DeleteCu } pb := pathBuilder{} pb.literal("/api/2.0/apps-settings/templates/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -963,7 +1003,7 @@ func (c *internalClient) DeleteCustomTemplate(ctx context.Context, req *DeleteCu } // Deletes an app space. -func (c *internalClient) deleteSpaceBase(ctx context.Context, req *DeleteSpaceRequest, opts ...call.Option) (*Operation, error) { +func (c *internalClient) deleteSpaceBase(ctx context.Context, req DeleteSpaceRequest, opts ...call.Option) (*Operation, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -977,7 +1017,11 @@ func (c *internalClient) deleteSpaceBase(ctx context.Context, req *DeleteSpaceRe } pb := pathBuilder{} pb.literal("/api/2.0/app-spaces/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1023,7 +1067,7 @@ func (c *internalClient) deleteSpaceBase(ctx context.Context, req *DeleteSpaceRe } // Deletes an app space. -func (c *internalClient) DeleteSpace(ctx context.Context, req *DeleteSpaceRequest, opts ...call.Option) (*DeleteSpaceOperation, error) { +func (c *internalClient) DeleteSpace(ctx context.Context, req DeleteSpaceRequest, opts ...call.Option) (*DeleteSpaceOperation, error) { operation, err := c.deleteSpaceBase(ctx, req, opts...) if err != nil { return nil, err @@ -1040,7 +1084,7 @@ func (c *internalClient) DeleteSpace(ctx context.Context, req *DeleteSpaceReques // DeleteSpaceOperation tracks the state of the long-running operation started by DeleteSpace. type DeleteSpaceOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -1066,7 +1110,7 @@ func (o *DeleteSpaceOperation) Metadata() (*Space, error) { // Done refreshes the operation and reports whether it has completed. func (o *DeleteSpaceOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -1083,7 +1127,7 @@ func (o *DeleteSpaceOperation) Done(ctx context.Context, opts ...call.Option) (b // Wait polls the operation until it completes. func (o *DeleteSpaceOperation) Wait(ctx context.Context, opts ...lro.Option) error { poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -1113,7 +1157,7 @@ func (o *DeleteSpaceOperation) Wait(ctx context.Context, opts ...lro.Option) err } // Retrieves information for the app with the supplied name. -func (c *internalClient) GetApp(ctx context.Context, req *GetAppRequest, opts ...call.Option) (*App, error) { +func (c *internalClient) GetApp(ctx context.Context, req GetAppRequest, opts ...call.Option) (*App, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1127,7 +1171,11 @@ func (c *internalClient) GetApp(ctx context.Context, req *GetAppRequest, opts .. } pb := pathBuilder{} pb.literal("/api/2.0/apps/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1174,7 +1222,7 @@ func (c *internalClient) GetApp(ctx context.Context, req *GetAppRequest, opts .. // Retrieves information for the app deployment with the supplied name and // deployment id. -func (c *internalClient) GetAppDeployment(ctx context.Context, req *GetAppDeploymentRequest, opts ...call.Option) (*AppDeployment, error) { +func (c *internalClient) GetAppDeployment(ctx context.Context, req GetAppDeploymentRequest, opts ...call.Option) (*AppDeployment, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1188,9 +1236,17 @@ func (c *internalClient) GetAppDeployment(ctx context.Context, req *GetAppDeploy } pb := pathBuilder{} pb.literal("/api/2.0/apps/") - pb.singleSegment(*req.AppName) + if req.AppName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.AppName) + } pb.literal("/deployments/") - pb.singleSegment(*req.DeploymentId) + if req.DeploymentId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DeploymentId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1236,7 +1292,7 @@ func (c *internalClient) GetAppDeployment(ctx context.Context, req *GetAppDeploy } // Gets the status of an app update. -func (c *internalClient) GetAppUpdate(ctx context.Context, req *GetAppUpdateRequest, opts ...call.Option) (*AppUpdate, error) { +func (c *internalClient) GetAppUpdate(ctx context.Context, req GetAppUpdateRequest, opts ...call.Option) (*AppUpdate, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1250,7 +1306,11 @@ func (c *internalClient) GetAppUpdate(ctx context.Context, req *GetAppUpdateRequ } pb := pathBuilder{} pb.literal("/api/2.0/apps/") - pb.singleSegment(*req.AppName) + if req.AppName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.AppName) + } pb.literal("/update") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1297,7 +1357,7 @@ func (c *internalClient) GetAppUpdate(ctx context.Context, req *GetAppUpdateRequ } // Gets the custom template with the specified name. -func (c *internalClient) GetCustomTemplate(ctx context.Context, req *GetCustomTemplateRequest, opts ...call.Option) (*CustomTemplate, error) { +func (c *internalClient) GetCustomTemplate(ctx context.Context, req GetCustomTemplateRequest, opts ...call.Option) (*CustomTemplate, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1311,7 +1371,11 @@ func (c *internalClient) GetCustomTemplate(ctx context.Context, req *GetCustomTe } pb := pathBuilder{} pb.literal("/api/2.0/apps-settings/templates/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1357,7 +1421,7 @@ func (c *internalClient) GetCustomTemplate(ctx context.Context, req *GetCustomTe } // Retrieves information for the app space with the supplied name. -func (c *internalClient) GetSpace(ctx context.Context, req *GetSpaceRequest, opts ...call.Option) (*Space, error) { +func (c *internalClient) GetSpace(ctx context.Context, req GetSpaceRequest, opts ...call.Option) (*Space, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1371,7 +1435,11 @@ func (c *internalClient) GetSpace(ctx context.Context, req *GetSpaceRequest, opt } pb := pathBuilder{} pb.literal("/api/2.0/app-spaces/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1417,7 +1485,7 @@ func (c *internalClient) GetSpace(ctx context.Context, req *GetSpaceRequest, opt } // Gets the status of an app space update operation. -func (c *internalClient) getSpaceOperation(ctx context.Context, req *GetOperationRequest, opts ...call.Option) (*Operation, error) { +func (c *internalClient) getSpaceOperation(ctx context.Context, req GetOperationRequest, opts ...call.Option) (*Operation, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1431,7 +1499,11 @@ func (c *internalClient) getSpaceOperation(ctx context.Context, req *GetOperatio } pb := pathBuilder{} pb.literal("/api/2.0/app-spaces/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/operation") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1478,8 +1550,8 @@ func (c *internalClient) getSpaceOperation(ctx context.Context, req *GetOperatio } // Lists all app deployments for the app with the supplied name. -func (c *internalClient) ListAppDeployments(ctx context.Context, req *ListAppDeploymentsRequest, opts ...call.Option) (*ListAppDeploymentsResponse, error) { - wireReq, err := listAppDeploymentsRequestToWire(req) +func (c *internalClient) ListAppDeployments(ctx context.Context, req ListAppDeploymentsRequest, opts ...call.Option) (*ListAppDeploymentsResponse, error) { + wireReq, err := listAppDeploymentsRequestToWire(&req) if err != nil { return nil, err } @@ -1496,7 +1568,11 @@ func (c *internalClient) ListAppDeployments(ctx context.Context, req *ListAppDep } pb := pathBuilder{} pb.literal("/api/2.0/apps/") - pb.singleSegment(*req.AppName) + if req.AppName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.AppName) + } pb.literal("/deployments") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1553,7 +1629,7 @@ func (c *internalClient) ListAppDeployments(ctx context.Context, req *ListAppDep // // For example: // -// for item, err := range c.ListAppDeploymentsIter(ctx, &ListAppDeploymentsRequest{}) { +// for item, err := range c.ListAppDeploymentsIter(ctx, ListAppDeploymentsRequest{}) { // if err != nil { // return err // } @@ -1565,16 +1641,13 @@ func (c *internalClient) ListAppDeployments(ctx context.Context, req *ListAppDep // // Callers who need custom pagination logic should use // ListAppDeployments directly. -func (c *internalClient) ListAppDeploymentsIter(ctx context.Context, req *ListAppDeploymentsRequest, opts ...call.Option) iter.Seq2[*AppDeployment, error] { +func (c *internalClient) ListAppDeploymentsIter(ctx context.Context, req ListAppDeploymentsRequest, opts ...call.Option) iter.Seq2[*AppDeployment, error] { return func(yield func(*AppDeployment, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListAppDeploymentsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListAppDeployments(ctx, &pageReq, opts...) + resp, err := c.ListAppDeployments(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1593,8 +1666,8 @@ func (c *internalClient) ListAppDeploymentsIter(ctx context.Context, req *ListAp } // Lists all apps in the workspace. -func (c *internalClient) ListApps(ctx context.Context, req *ListAppsRequest, opts ...call.Option) (*ListAppsResponse, error) { - wireReq, err := listAppsRequestToWire(req) +func (c *internalClient) ListApps(ctx context.Context, req ListAppsRequest, opts ...call.Option) (*ListAppsResponse, error) { + wireReq, err := listAppsRequestToWire(&req) if err != nil { return nil, err } @@ -1667,7 +1740,7 @@ func (c *internalClient) ListApps(ctx context.Context, req *ListAppsRequest, opt // // For example: // -// for item, err := range c.ListAppsIter(ctx, &ListAppsRequest{}) { +// for item, err := range c.ListAppsIter(ctx, ListAppsRequest{}) { // if err != nil { // return err // } @@ -1679,16 +1752,13 @@ func (c *internalClient) ListApps(ctx context.Context, req *ListAppsRequest, opt // // Callers who need custom pagination logic should use // ListApps directly. -func (c *internalClient) ListAppsIter(ctx context.Context, req *ListAppsRequest, opts ...call.Option) iter.Seq2[*App, error] { +func (c *internalClient) ListAppsIter(ctx context.Context, req ListAppsRequest, opts ...call.Option) iter.Seq2[*App, error] { return func(yield func(*App, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListAppsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListApps(ctx, &pageReq, opts...) + resp, err := c.ListApps(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1707,8 +1777,8 @@ func (c *internalClient) ListAppsIter(ctx context.Context, req *ListAppsRequest, } // Lists all custom templates in the workspace. -func (c *internalClient) ListCustomTemplates(ctx context.Context, req *ListCustomTemplatesRequest, opts ...call.Option) (*ListCustomTemplatesResponse, error) { - wireReq, err := listCustomTemplatesRequestToWire(req) +func (c *internalClient) ListCustomTemplates(ctx context.Context, req ListCustomTemplatesRequest, opts ...call.Option) (*ListCustomTemplatesResponse, error) { + wireReq, err := listCustomTemplatesRequestToWire(&req) if err != nil { return nil, err } @@ -1778,7 +1848,7 @@ func (c *internalClient) ListCustomTemplates(ctx context.Context, req *ListCusto // // For example: // -// for item, err := range c.ListCustomTemplatesIter(ctx, &ListCustomTemplatesRequest{}) { +// for item, err := range c.ListCustomTemplatesIter(ctx, ListCustomTemplatesRequest{}) { // if err != nil { // return err // } @@ -1790,16 +1860,13 @@ func (c *internalClient) ListCustomTemplates(ctx context.Context, req *ListCusto // // Callers who need custom pagination logic should use // ListCustomTemplates directly. -func (c *internalClient) ListCustomTemplatesIter(ctx context.Context, req *ListCustomTemplatesRequest, opts ...call.Option) iter.Seq2[*CustomTemplate, error] { +func (c *internalClient) ListCustomTemplatesIter(ctx context.Context, req ListCustomTemplatesRequest, opts ...call.Option) iter.Seq2[*CustomTemplate, error] { return func(yield func(*CustomTemplate, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListCustomTemplatesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListCustomTemplates(ctx, &pageReq, opts...) + resp, err := c.ListCustomTemplates(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1818,8 +1885,8 @@ func (c *internalClient) ListCustomTemplatesIter(ctx context.Context, req *ListC } // Lists all app spaces in the workspace. -func (c *internalClient) ListSpaces(ctx context.Context, req *ListSpacesRequest, opts ...call.Option) (*ListSpacesResponse, error) { - wireReq, err := listSpacesRequestToWire(req) +func (c *internalClient) ListSpaces(ctx context.Context, req ListSpacesRequest, opts ...call.Option) (*ListSpacesResponse, error) { + wireReq, err := listSpacesRequestToWire(&req) if err != nil { return nil, err } @@ -1889,7 +1956,7 @@ func (c *internalClient) ListSpaces(ctx context.Context, req *ListSpacesRequest, // // For example: // -// for item, err := range c.ListSpacesIter(ctx, &ListSpacesRequest{}) { +// for item, err := range c.ListSpacesIter(ctx, ListSpacesRequest{}) { // if err != nil { // return err // } @@ -1901,16 +1968,13 @@ func (c *internalClient) ListSpaces(ctx context.Context, req *ListSpacesRequest, // // Callers who need custom pagination logic should use // ListSpaces directly. -func (c *internalClient) ListSpacesIter(ctx context.Context, req *ListSpacesRequest, opts ...call.Option) iter.Seq2[*Space, error] { +func (c *internalClient) ListSpacesIter(ctx context.Context, req ListSpacesRequest, opts ...call.Option) iter.Seq2[*Space, error] { return func(yield func(*Space, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListSpacesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListSpaces(ctx, &pageReq, opts...) + resp, err := c.ListSpaces(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1929,8 +1993,8 @@ func (c *internalClient) ListSpacesIter(ctx context.Context, req *ListSpacesRequ } // Start the last active deployment of the app in the workspace. -func (c *internalClient) startAppBase(ctx context.Context, req *StartAppRequest, opts ...call.Option) (*App, error) { - wireReq, err := startAppRequestToWire(req) +func (c *internalClient) startAppBase(ctx context.Context, req StartAppRequest, opts ...call.Option) (*App, error) { + wireReq, err := startAppRequestToWire(&req) if err != nil { return nil, err } @@ -1951,7 +2015,11 @@ func (c *internalClient) startAppBase(ctx context.Context, req *StartAppRequest, } pb := pathBuilder{} pb.literal("/api/2.0/apps/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/start") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1999,7 +2067,7 @@ func (c *internalClient) startAppBase(ctx context.Context, req *StartAppRequest, } // Start the last active deployment of the app in the workspace. -func (c *internalClient) StartApp(ctx context.Context, req *StartAppRequest, opts ...call.Option) (*StartAppWaiter, error) { +func (c *internalClient) StartApp(ctx context.Context, req StartAppRequest, opts ...call.Option) (*StartAppWaiter, error) { if req.Name == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "Name") } @@ -2016,13 +2084,18 @@ func (c *internalClient) StartApp(ctx context.Context, req *StartAppRequest, opt // StartAppWaiter tracks the state of the operation started by StartApp. type StartAppWaiter struct { - poll func(context.Context, *GetAppRequest, ...call.Option) (*App, error) + poll func(context.Context, GetAppRequest, ...call.Option) (*App, error) name string } +// GetName returns the Name value used to identify the operation. +func (w *StartAppWaiter) GetName() string { + return w.name +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *StartAppWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetAppRequest{ + pollResp, err := w.poll(ctx, GetAppRequest{ Name: &w.name, }, opts...) if err != nil { @@ -2050,7 +2123,7 @@ func (w *StartAppWaiter) Done(ctx context.Context, opts ...call.Option) (bool, e func (w *StartAppWaiter) Wait(ctx context.Context, opts ...lro.Option) (*App, error) { var result *App poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetAppRequest{ + pollResp, err := w.poll(ctx, GetAppRequest{ Name: &w.name, }) if err != nil { @@ -2087,8 +2160,8 @@ func (w *StartAppWaiter) Wait(ctx context.Context, opts ...lro.Option) (*App, er } // Stops the active deployment of the app in the workspace. -func (c *internalClient) stopAppBase(ctx context.Context, req *StopAppRequest, opts ...call.Option) (*App, error) { - wireReq, err := stopAppRequestToWire(req) +func (c *internalClient) stopAppBase(ctx context.Context, req StopAppRequest, opts ...call.Option) (*App, error) { + wireReq, err := stopAppRequestToWire(&req) if err != nil { return nil, err } @@ -2109,7 +2182,11 @@ func (c *internalClient) stopAppBase(ctx context.Context, req *StopAppRequest, o } pb := pathBuilder{} pb.literal("/api/2.0/apps/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/stop") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -2157,7 +2234,7 @@ func (c *internalClient) stopAppBase(ctx context.Context, req *StopAppRequest, o } // Stops the active deployment of the app in the workspace. -func (c *internalClient) StopApp(ctx context.Context, req *StopAppRequest, opts ...call.Option) (*StopAppWaiter, error) { +func (c *internalClient) StopApp(ctx context.Context, req StopAppRequest, opts ...call.Option) (*StopAppWaiter, error) { if req.Name == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "Name") } @@ -2174,13 +2251,18 @@ func (c *internalClient) StopApp(ctx context.Context, req *StopAppRequest, opts // StopAppWaiter tracks the state of the operation started by StopApp. type StopAppWaiter struct { - poll func(context.Context, *GetAppRequest, ...call.Option) (*App, error) + poll func(context.Context, GetAppRequest, ...call.Option) (*App, error) name string } +// GetName returns the Name value used to identify the operation. +func (w *StopAppWaiter) GetName() string { + return w.name +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *StopAppWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetAppRequest{ + pollResp, err := w.poll(ctx, GetAppRequest{ Name: &w.name, }, opts...) if err != nil { @@ -2208,7 +2290,7 @@ func (w *StopAppWaiter) Done(ctx context.Context, opts ...call.Option) (bool, er func (w *StopAppWaiter) Wait(ctx context.Context, opts ...lro.Option) (*App, error) { var result *App poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetAppRequest{ + pollResp, err := w.poll(ctx, GetAppRequest{ Name: &w.name, }) if err != nil { @@ -2245,8 +2327,8 @@ func (w *StopAppWaiter) Wait(ctx context.Context, opts ...lro.Option) (*App, err } // Updates the app with the supplied name. -func (c *internalClient) UpdateApp(ctx context.Context, req *UpdateAppRequest, opts ...call.Option) (*App, error) { - wireReq, err := updateAppRequestToWire(req) +func (c *internalClient) UpdateApp(ctx context.Context, req UpdateAppRequest, opts ...call.Option) (*App, error) { + wireReq, err := updateAppRequestToWire(&req) if err != nil { return nil, err } @@ -2267,7 +2349,11 @@ func (c *internalClient) UpdateApp(ctx context.Context, req *UpdateAppRequest, o } pb := pathBuilder{} pb.literal("/api/2.0/apps/") - pb.singleSegment(*req.App.Name) + if req.App == nil || req.App.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.App.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2314,8 +2400,8 @@ func (c *internalClient) UpdateApp(ctx context.Context, req *UpdateAppRequest, o } // Updates the thumbnail for an app. -func (c *internalClient) UpdateAppThumbnail(ctx context.Context, req *UpdateAppThumbnailRequest, opts ...call.Option) (*AppThumbnail, error) { - wireReq, err := updateAppThumbnailRequestToWire(req) +func (c *internalClient) UpdateAppThumbnail(ctx context.Context, req UpdateAppThumbnailRequest, opts ...call.Option) (*AppThumbnail, error) { + wireReq, err := updateAppThumbnailRequestToWire(&req) if err != nil { return nil, err } @@ -2336,7 +2422,11 @@ func (c *internalClient) UpdateAppThumbnail(ctx context.Context, req *UpdateAppT } pb := pathBuilder{} pb.literal("/api/2.0/apps/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/thumbnail") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -2385,8 +2475,8 @@ func (c *internalClient) UpdateAppThumbnail(ctx context.Context, req *UpdateAppT // Updates the custom template with the specified name. Note that the template // name cannot be updated. -func (c *internalClient) UpdateCustomTemplate(ctx context.Context, req *UpdateCustomTemplateRequest, opts ...call.Option) (*CustomTemplate, error) { - wireReq, err := updateCustomTemplateRequestToWire(req) +func (c *internalClient) UpdateCustomTemplate(ctx context.Context, req UpdateCustomTemplateRequest, opts ...call.Option) (*CustomTemplate, error) { + wireReq, err := updateCustomTemplateRequestToWire(&req) if err != nil { return nil, err } @@ -2407,7 +2497,11 @@ func (c *internalClient) UpdateCustomTemplate(ctx context.Context, req *UpdateCu } pb := pathBuilder{} pb.literal("/api/2.0/apps-settings/templates/") - pb.singleSegment(*req.Template.Name) + if req.Template == nil || req.Template.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Template.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2455,8 +2549,8 @@ func (c *internalClient) UpdateCustomTemplate(ctx context.Context, req *UpdateCu // Updates an app space. The update process is asynchronous and the status of // the update can be checked with the GetSpaceOperation method. -func (c *internalClient) updateSpaceBase(ctx context.Context, req *UpdateSpaceRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := updateSpaceRequestToWire(req) +func (c *internalClient) updateSpaceBase(ctx context.Context, req UpdateSpaceRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := updateSpaceRequestToWire(&req) if err != nil { return nil, err } @@ -2477,7 +2571,11 @@ func (c *internalClient) updateSpaceBase(ctx context.Context, req *UpdateSpaceRe } pb := pathBuilder{} pb.literal("/api/2.0/app-spaces/") - pb.singleSegment(*req.Space.Name) + if req.Space == nil || req.Space.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Space.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -2528,7 +2626,7 @@ func (c *internalClient) updateSpaceBase(ctx context.Context, req *UpdateSpaceRe // Updates an app space. The update process is asynchronous and the status of // the update can be checked with the GetSpaceOperation method. -func (c *internalClient) UpdateSpace(ctx context.Context, req *UpdateSpaceRequest, opts ...call.Option) (*UpdateSpaceOperation, error) { +func (c *internalClient) UpdateSpace(ctx context.Context, req UpdateSpaceRequest, opts ...call.Option) (*UpdateSpaceOperation, error) { operation, err := c.updateSpaceBase(ctx, req, opts...) if err != nil { return nil, err @@ -2545,7 +2643,7 @@ func (c *internalClient) UpdateSpace(ctx context.Context, req *UpdateSpaceReques // UpdateSpaceOperation tracks the state of the long-running operation started by UpdateSpace. type UpdateSpaceOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -2571,7 +2669,7 @@ func (o *UpdateSpaceOperation) Metadata() (*SpaceUpdate, error) { // Done refreshes the operation and reports whether it has completed. func (o *UpdateSpaceOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -2589,7 +2687,7 @@ func (o *UpdateSpaceOperation) Done(ctx context.Context, opts ...call.Option) (b func (o *UpdateSpaceOperation) Wait(ctx context.Context, opts ...lro.Option) (*Space, error) { var result *Space poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } diff --git a/apps/v1/genhelper.go b/apps/v1/genhelper.go old mode 100755 new mode 100644 index 088db1d..6b36f81 --- a/apps/v1/genhelper.go +++ b/apps/v1/genhelper.go @@ -206,11 +206,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -223,13 +224,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/apps/v1/model.go b/apps/v1/model.go old mode 100755 new mode 100644 index 414a3e2..8eb984f --- a/apps/v1/model.go +++ b/apps/v1/model.go @@ -1453,6 +1453,10 @@ type Space struct { UsagePolicyId *string `fieldmask:"usage_policy_id"` // The effective usage policy ID used by apps in the space. EffectiveUsagePolicyId *string `fieldmask:"effective_usage_policy_id"` + // The group whose permissions users assume via Role Authorization for apps in + // this space. When set, user tokens assume the role of this group instead of + // doing regular obo token downscoping. Set only at space creation. + AssumeGroupId *string `fieldmask:"assume_group_id"` } type SpaceStatus struct { diff --git a/apps/v1/wire.go b/apps/v1/wire.go old mode 100755 new mode 100644 index fc31765..f21a417 --- a/apps/v1/wire.go +++ b/apps/v1/wire.go @@ -3,12 +3,57 @@ package apps import ( + "bytes" "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + func fieldMaskToWire[T any](mask *types.FieldMask[T]) *string { if mask == nil { return nil @@ -49,7 +94,7 @@ type appWire struct { Updater *string `json:"updater,omitempty"` PendingDeployment *appDeploymentWire `json:"pending_deployment,omitempty"` Resources []appResourceWire `json:"resources,omitempty"` - ServicePrincipalId *int64 `json:"service_principal_id,omitempty"` + ServicePrincipalId *wireInt64 `json:"service_principal_id,omitempty"` ServicePrincipalName *string `json:"service_principal_name,omitempty"` DefaultSourceCodePath *string `json:"default_source_code_path,omitempty"` DefaultGitSource *gitSourceWire `json:"default_git_source,omitempty"` @@ -99,6 +144,10 @@ func appToWire(v *App) (*appWire, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "App.Resources", err) } + servicePrincipalIdWireValue, err := int64ToWire(v.ServicePrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "App.ServicePrincipalId", err) + } defaultGitSourceWireValue, err := gitSourceToWire(v.DefaultGitSource) if err != nil { return nil, fmt.Errorf("%s: %w", "App.DefaultGitSource", err) @@ -143,7 +192,7 @@ func appToWire(v *App) (*appWire, error) { Updater: v.Updater, PendingDeployment: pendingDeploymentWireValue, Resources: resourcesWireValue, - ServicePrincipalId: v.ServicePrincipalId, + ServicePrincipalId: servicePrincipalIdWireValue, ServicePrincipalName: v.ServicePrincipalName, DefaultSourceCodePath: v.DefaultSourceCodePath, DefaultGitSource: defaultGitSourceWireValue, @@ -204,6 +253,10 @@ func appFromWire(w *appWire) (*App, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "App.Resources", err) } + servicePrincipalIdPublicValue, err := int64FromWire(w.ServicePrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "App.ServicePrincipalId", err) + } defaultGitSourcePublicValue, err := gitSourceFromWire(w.DefaultGitSource) if err != nil { return nil, fmt.Errorf("%s: %w", "App.DefaultGitSource", err) @@ -240,7 +293,7 @@ func appFromWire(w *appWire) (*App, error) { Updater: w.Updater, PendingDeployment: pendingDeploymentPublicValue, Resources: resourcesPublicValue, - ServicePrincipalId: w.ServicePrincipalId, + ServicePrincipalId: servicePrincipalIdPublicValue, ServicePrincipalName: w.ServicePrincipalName, DefaultSourceCodePath: w.DefaultSourceCodePath, DefaultGitSource: defaultGitSourcePublicValue, @@ -1574,21 +1627,25 @@ func envVarFromWire(w *envVarWire) (*EnvVar, error) { } type gitRepositoryWire struct { - Url *string `json:"url,omitempty"` - Provider *string `json:"provider,omitempty"` - AutoDeploy *bool `json:"auto_deploy,omitempty"` - CallerCredentialId *int64 `json:"caller_credential_id,omitempty"` + Url *string `json:"url,omitempty"` + Provider *string `json:"provider,omitempty"` + AutoDeploy *bool `json:"auto_deploy,omitempty"` + CallerCredentialId *wireInt64 `json:"caller_credential_id,omitempty"` } func gitRepositoryToWire(v *GitRepository) (*gitRepositoryWire, error) { if v == nil { return nil, nil } + callerCredentialIdWireValue, err := int64ToWire(v.CallerCredentialId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GitRepository.CallerCredentialId", err) + } return &gitRepositoryWire{ Url: v.Url, Provider: v.Provider, AutoDeploy: v.AutoDeploy, - CallerCredentialId: v.CallerCredentialId, + CallerCredentialId: callerCredentialIdWireValue, }, nil } @@ -1596,11 +1653,15 @@ func gitRepositoryFromWire(w *gitRepositoryWire) (*GitRepository, error) { if w == nil { return nil, nil } + callerCredentialIdPublicValue, err := int64FromWire(w.CallerCredentialId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GitRepository.CallerCredentialId", err) + } return &GitRepository{ Url: w.Url, Provider: w.Provider, AutoDeploy: w.AutoDeploy, - CallerCredentialId: w.CallerCredentialId, + CallerCredentialId: callerCredentialIdPublicValue, }, nil } @@ -1882,11 +1943,12 @@ type spaceWire struct { Resources []appResourceWire `json:"resources,omitempty"` UserApiScopes []string `json:"user_api_scopes,omitempty"` EffectiveUserApiScopes []string `json:"effective_user_api_scopes,omitempty"` - ServicePrincipalId *int64 `json:"service_principal_id,omitempty"` + ServicePrincipalId *wireInt64 `json:"service_principal_id,omitempty"` ServicePrincipalName *string `json:"service_principal_name,omitempty"` ServicePrincipalClientId *string `json:"service_principal_client_id,omitempty"` UsagePolicyId *string `json:"usage_policy_id,omitempty"` EffectiveUsagePolicyId *string `json:"effective_usage_policy_id,omitempty"` + AssumeGroupId *string `json:"assume_group_id,omitempty"` } func spaceToWire(v *Space) (*spaceWire, error) { @@ -1901,6 +1963,10 @@ func spaceToWire(v *Space) (*spaceWire, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "Space.Resources", err) } + servicePrincipalIdWireValue, err := int64ToWire(v.ServicePrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Space.ServicePrincipalId", err) + } return &spaceWire{ Name: v.Name, Description: v.Description, @@ -1913,11 +1979,12 @@ func spaceToWire(v *Space) (*spaceWire, error) { Resources: resourcesWireValue, UserApiScopes: v.UserApiScopes, EffectiveUserApiScopes: v.EffectiveUserApiScopes, - ServicePrincipalId: v.ServicePrincipalId, + ServicePrincipalId: servicePrincipalIdWireValue, ServicePrincipalName: v.ServicePrincipalName, ServicePrincipalClientId: v.ServicePrincipalClientId, UsagePolicyId: v.UsagePolicyId, EffectiveUsagePolicyId: v.EffectiveUsagePolicyId, + AssumeGroupId: v.AssumeGroupId, }, nil } @@ -1933,6 +2000,10 @@ func spaceFromWire(w *spaceWire) (*Space, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "Space.Resources", err) } + servicePrincipalIdPublicValue, err := int64FromWire(w.ServicePrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Space.ServicePrincipalId", err) + } return &Space{ Name: w.Name, Description: w.Description, @@ -1945,11 +2016,12 @@ func spaceFromWire(w *spaceWire) (*Space, error) { Resources: resourcesPublicValue, UserApiScopes: w.UserApiScopes, EffectiveUserApiScopes: w.EffectiveUserApiScopes, - ServicePrincipalId: w.ServicePrincipalId, + ServicePrincipalId: servicePrincipalIdPublicValue, ServicePrincipalName: w.ServicePrincipalName, ServicePrincipalClientId: w.ServicePrincipalClientId, UsagePolicyId: w.UsagePolicyId, EffectiveUsagePolicyId: w.EffectiveUsagePolicyId, + AssumeGroupId: w.AssumeGroupId, }, nil } diff --git a/auth/CHANGELOG.md b/auth/CHANGELOG.md index 6224c04..19f237c 100644 --- a/auth/CHANGELOG.md +++ b/auth/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/auth/credentials/default.go b/auth/credentials/default.go index d5c6a17..a4cbbe4 100644 --- a/auth/credentials/default.go +++ b/auth/credentials/default.go @@ -4,15 +4,20 @@ import ( "context" "errors" "fmt" + "os" "sync" "sync/atomic" + "github.com/databricks/databricks-sdk-go/credentials/u2m" "github.com/databricks/sdk-go/auth" + "github.com/databricks/sdk-go/auth/oidc" "github.com/databricks/sdk-go/core/profiles" ) const authDocURL = "https://docs.databricks.com/aws/en/dev-tools/auth/index" +const defaultOIDCTokenEnv = "DATABRICKS_OIDC_TOKEN" + var ( // ErrNoAuthConfigured is returned when no strategy in the default chain // could be configured from the resolved profile and environment. @@ -28,19 +33,40 @@ var ( // when the strategy does not apply to the given profile, so the chain can move // on to the next strategy. type strategy struct { - name string - configure func(profiles.Profile) (auth.Credentials, error) + name string + supportsGroupAssumption bool + configure func(profiles.Profile) (auth.Credentials, error) } // defaultStrategies returns the strategies tried by [NewDefaultCredentials], in -// priority order: PAT, then OAuth M2M, then the Databricks CLI (U2M). The order -// mirrors the other Databricks SDKs and must not change without consideration -// for environments compatible with more than one strategy. +// priority order. The order mirrors the other Databricks SDKs and must not +// change without considering environments compatible with more than one +// strategy. func defaultStrategies() []strategy { return []strategy{ - {name: "pat", configure: configurePAT}, - {name: "oauth-m2m", configure: configureM2M}, - {name: "databricks-cli", configure: configureU2M}, + { + name: "pat", + configure: configurePAT, + }, + { + name: "oauth-m2m", + supportsGroupAssumption: true, + configure: configureM2M, + }, + { + name: "databricks-cli", + configure: configureU2M, + }, + { + name: "env-oidc", + supportsGroupAssumption: true, + configure: configureEnvOIDC, + }, + { + name: "file-oidc", + supportsGroupAssumption: true, + configure: configureFileOIDC, + }, } } @@ -59,6 +85,8 @@ type DefaultCredentialsOptions struct { // 1. PAT (pat). // 2. OAuth M2M (oauth-m2m). // 3. Databricks CLI (databricks-cli). +// 4. Environment OIDC (env-oidc). +// 5. File OIDC (file-oidc). // // If the profile sets auth_type, only the strategy with that name is tried. // Resolution is deferred until the first [auth.Credentials.AuthHeaders] call @@ -131,6 +159,9 @@ func (c *defaultCredentials) resolveChain() (auth.Credentials, error) { } for _, s := range c.strategies { + if profile.GroupID != "" && !s.supportsGroupAssumption { + continue + } creds, err := s.configure(profile) if err != nil { return nil, err @@ -147,6 +178,9 @@ func (c *defaultCredentials) resolveByAuthType(profile profiles.Profile, authTyp if s.name != authType { continue } + if profile.GroupID != "" && !s.supportsGroupAssumption { + return nil, fmt.Errorf("auth type %q does not support group role assumption. Use OAuth M2M or Workload Identity Federation", authType) + } creds, err := s.configure(profile) if err != nil { return nil, err @@ -179,6 +213,7 @@ func configureM2M(p profiles.Profile) (auth.Credentials, error) { Host: p.Host, ClientID: p.ClientID, ClientSecret: string(p.ClientSecret), + GroupID: p.GroupID, }) if err != nil { return nil, err @@ -204,3 +239,47 @@ func configureU2M(p profiles.Profile) (auth.Credentials, error) { } return auth.NewTokenCredentials("databricks-cli", auth.NewCachedTokenProvider(provider)), nil } + +func configureEnvOIDC(profile profiles.Profile) (auth.Credentials, error) { + name := profile.OIDCTokenEnv + if name == "" { + name = defaultOIDCTokenEnv + } + if profile.Host == "" || os.Getenv(name) == "" { + return nil, nil + } + return newOIDCCredentials(profile, "env-oidc", oidc.NewEnvIDTokenProvider(name)), nil +} + +func configureFileOIDC(profile profiles.Profile) (auth.Credentials, error) { + if profile.Host == "" || profile.OIDCTokenFilePath == "" { + return nil, nil + } + return newOIDCCredentials(profile, "file-oidc", oidc.NewFileTokenProvider(profile.OIDCTokenFilePath)), nil +} + +func newOIDCCredentials(profile profiles.Profile, name string, idTokenProvider oidc.IDTokenProvider) auth.Credentials { + tokenProvider := oidc.NewDatabricksOIDCTokenProvider(oidc.DatabricksOIDCTokenProviderConfig{ + ClientID: profile.ClientID, + AccountID: profile.AccountID, + Host: profile.Host, + GroupID: profile.GroupID, + TokenEndpointProvider: oidcTokenEndpointProvider(profile), + Audience: profile.TokenAudience, + IDTokenProvider: idTokenProvider, + }) + return auth.NewTokenCredentials(name, auth.NewCachedTokenProvider(tokenProvider)) +} + +func oidcTokenEndpointProvider(profile profiles.Profile) func(context.Context) (*u2m.OAuthAuthorizationServer, error) { + return func(ctx context.Context) (*u2m.OAuthAuthorizationServer, error) { + server, err := discoverAuthorizationServer(ctx, nil, profile.Host) + if err != nil { + return nil, err + } + return &u2m.OAuthAuthorizationServer{ + AuthorizationEndpoint: server.AuthorizationEndpoint, + TokenEndpoint: server.TokenEndpoint, + }, nil + } +} diff --git a/auth/credentials/default_test.go b/auth/credentials/default_test.go index a9341c0..fde3319 100644 --- a/auth/credentials/default_test.go +++ b/auth/credentials/default_test.go @@ -3,6 +3,9 @@ package credentials import ( "context" "errors" + "os" + "slices" + "strings" "sync" "testing" @@ -13,11 +16,18 @@ import ( const testHost = "https://workspace.example" +func isolateOIDCEnvironment(t *testing.T) { + t.Helper() + t.Setenv(defaultOIDCTokenEnv, "") + t.Setenv("TEST_OIDC_TOKEN", "") +} + // configuredStrategy returns a strategy that always builds credentials whose // single auth header identifies the strategy by label. func configuredStrategy(label string) strategy { return strategy{ - name: label, + name: label, + supportsGroupAssumption: true, configure: func(profiles.Profile) (auth.Credentials, error) { return auth.NewTokenCredentials(label, auth.TokenProviderFn( func(context.Context) (*auth.Token, error) { @@ -44,44 +54,139 @@ func newTestChain(strategies []strategy, p profiles.Profile) *defaultCredentials return &defaultCredentials{loadProfile: loaderFor(p), strategies: strategies} } +func TestDefaultStrategies_Order(t *testing.T) { + strategies := defaultStrategies() + got := make([]string, len(strategies)) + for i, strategy := range strategies { + got[i] = strategy.name + } + want := []string{ + "pat", + "oauth-m2m", + "databricks-cli", + "env-oidc", + "file-oidc", + } + if !slices.Equal(got, want) { + t.Errorf("default strategy order = %v, want %v", got, want) + } +} + func TestDefaultCredentials_Resolution(t *testing.T) { + executable, err := os.Executable() + if err != nil { + t.Fatalf("os.Executable() error = %v", err) + } + testCases := []struct { - desc string + name string strategies []strategy profile profiles.Profile - wantValue string // expected bearer token value in the Authorization header + setEnv func(*testing.T) + wantName string }{ { - desc: "returns the first configured strategy", + name: "returns the first configured strategy", strategies: []strategy{{name: "pat", configure: configurePAT}, configuredStrategy("oauth-m2m")}, profile: profiles.Profile{Host: testHost, Token: "dapi-abc"}, - wantValue: "dapi-abc", + wantName: "pat", }, { - desc: "falls through to the next strategy when earlier ones are unconfigured", + name: "falls through to the next strategy when earlier ones are unconfigured", strategies: []strategy{unconfiguredStrategy("pat"), configuredStrategy("oauth-m2m")}, profile: profiles.Profile{Host: testHost}, - wantValue: "oauth-m2m", + wantName: "oauth-m2m", }, { - // PAT is configured and comes first, but auth_type pins oauth-m2m. - desc: "selects the strategy named by auth_type over an earlier configured strategy", + name: "auth_type pins a strategy over an earlier configured strategy", strategies: []strategy{{name: "pat", configure: configurePAT}, configuredStrategy("oauth-m2m")}, profile: profiles.Profile{Host: testHost, Token: "dapi-abc", AuthType: "oauth-m2m"}, - wantValue: "oauth-m2m", + wantName: "oauth-m2m", + }, + { + name: "auth_type pins environment OIDC when PAT is configured", + profile: profiles.Profile{Host: testHost, AuthType: "env-oidc", Token: "earlier-pat"}, + setEnv: func(t *testing.T) { + t.Setenv(defaultOIDCTokenEnv, "id-token") + }, + wantName: "env-oidc", + }, + { + name: "grouped file OIDC selected by auth_type", + profile: profiles.Profile{Host: testHost, AuthType: "file-oidc", OIDCTokenFilePath: "/missing", GroupID: "group-id"}, + wantName: "file-oidc", + }, + { + name: "grouped environment OIDC selected without auth_type", + profile: profiles.Profile{Host: testHost, GroupID: "group-id"}, + setEnv: func(t *testing.T) { + t.Setenv(defaultOIDCTokenEnv, "id-token") + }, + wantName: "env-oidc", + }, + { + name: "custom environment OIDC selected without auth_type", + profile: profiles.Profile{Host: testHost, OIDCTokenEnv: "TEST_OIDC_TOKEN"}, + setEnv: func(t *testing.T) { + t.Setenv("TEST_OIDC_TOKEN", "id-token") + }, + wantName: "env-oidc", + }, + { + name: "file OIDC selected without auth_type", + profile: profiles.Profile{Host: testHost, OIDCTokenFilePath: "/missing"}, + wantName: "file-oidc", + }, + { + name: "PAT precedes environment OIDC without auth_type", + profile: profiles.Profile{Host: testHost, Token: "earlier-pat"}, + setEnv: func(t *testing.T) { + t.Setenv(defaultOIDCTokenEnv, "id-token") + }, + wantName: "pat", + }, + { + name: "OAuth M2M precedes environment OIDC without auth_type", + profile: profiles.Profile{ + Host: testHost, + ClientID: "client-id", + ClientSecret: "client-secret", + }, + setEnv: func(t *testing.T) { + t.Setenv(defaultOIDCTokenEnv, "id-token") + }, + wantName: "oauth-m2m", + }, + { + name: "CLI precedes environment OIDC without auth_type", + profile: profiles.Profile{ + Name: "configured-profile", + Host: testHost, + DatabricksCLIPath: executable, + }, + setEnv: func(t *testing.T) { + t.Setenv(defaultOIDCTokenEnv, "id-token") + }, + wantName: "databricks-cli", }, } for _, tc := range testCases { - t.Run(tc.desc, func(t *testing.T) { - creds := newTestChain(tc.strategies, tc.profile) - headers, err := creds.AuthHeaders(context.Background()) + t.Run(tc.name, func(t *testing.T) { + isolateOIDCEnvironment(t) + if tc.setEnv != nil { + tc.setEnv(t) + } + strategies := tc.strategies + if strategies == nil { + strategies = defaultStrategies() + } + credentials, err := newTestChain(strategies, tc.profile).resolveChain() if err != nil { - t.Fatalf("AuthHeaders() error = %v", err) + t.Fatalf("resolveChain() error = %v", err) } - want := []auth.Header{{Key: "Authorization", Value: "Bearer " + tc.wantValue}} - if diff := cmp.Diff(want, headers); diff != "" { - t.Errorf("AuthHeaders() mismatch (-want +got):\n%s", diff) + if got := credentials.Name(); got != tc.wantName { + t.Errorf("Name() = %q, want %q", got, tc.wantName) } }) } @@ -158,11 +263,34 @@ func TestDefaultCredentials_Errors(t *testing.T) { profile: profiles.Profile{Host: testHost, AuthType: "pat"}, wantErr: ErrNoAuthConfigured, }, + { + desc: "environment OIDC token is missing", + profile: profiles.Profile{Host: testHost, AuthType: "env-oidc"}, + wantErr: ErrNoAuthConfigured, + }, + { + desc: "file OIDC path is missing", + profile: profiles.Profile{Host: testHost, AuthType: "file-oidc"}, + wantErr: ErrNoAuthConfigured, + }, + { + desc: "file OIDC host is missing", + profile: profiles.Profile{ + AuthType: "file-oidc", + OIDCTokenFilePath: "/token", + }, + wantErr: ErrNoAuthConfigured, + }, } for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { - creds := newTestChain(tc.strategies, tc.profile) + isolateOIDCEnvironment(t) + strategies := tc.strategies + if strategies == nil { + strategies = defaultStrategies() + } + creds := newTestChain(strategies, tc.profile) _, err := creds.AuthHeaders(context.Background()) if !errors.Is(err, tc.wantErr) { t.Errorf("AuthHeaders() err = %v, want %v", err, tc.wantErr) @@ -171,6 +299,230 @@ func TestDefaultCredentials_Errors(t *testing.T) { } } +// TestDefaultCredentials_GroupedResolutionSkipsUnsupportedStrategies verifies +// that automatic resolution bypasses strategies that cannot assume a group. +func TestDefaultCredentials_GroupedResolutionSkipsUnsupportedStrategies(t *testing.T) { + unsupportedCalls := 0 + unsupported := strategy{ + name: "pat", + configure: func(profiles.Profile) (auth.Credentials, error) { + unsupportedCalls++ + return NewPATCredentials("dapi-abc") + }, + } + + creds := newTestChain( + []strategy{unsupported, configuredStrategy("oauth-m2m")}, + profiles.Profile{GroupID: "group-id"}, + ) + + if _, err := creds.AuthHeaders(context.Background()); err != nil { + t.Fatalf("AuthHeaders() error = %v", err) + } + + if unsupportedCalls != 0 { + t.Errorf("unsupported configure calls = %d, want 0", unsupportedCalls) + } + + if got, want := creds.Name(), "oauth-m2m"; got != want { + t.Errorf("Name() = %q, want %q", got, want) + } +} + +// TestDefaultCredentials_GroupedExplicitAuthRejectsUnsupportedStrategy verifies +// that an explicitly selected unsupported strategy is rejected before it is +// configured. +func TestDefaultCredentials_GroupedExplicitAuthRejectsUnsupportedStrategy(t *testing.T) { + authTypes := []string{"pat", "databricks-cli"} + + for _, authType := range authTypes { + t.Run(authType, func(t *testing.T) { + configureCalls := 0 + s := strategy{ + name: authType, + configure: func(profiles.Profile) (auth.Credentials, error) { + configureCalls++ + return nil, errors.New("must not be called") + }, + } + + creds := newTestChain([]strategy{s}, profiles.Profile{GroupID: "group-id", AuthType: authType}) + + _, err := creds.AuthHeaders(context.Background()) + if err == nil || !strings.Contains(err.Error(), "does not support group role assumption") { + t.Fatalf("AuthHeaders() error = %v", err) + } + + if configureCalls != 0 { + t.Errorf("configure calls = %d, want 0", configureCalls) + } + }) + } +} + +// TestDefaultCredentials_GroupedChainExhaustionReturnsNoAuthConfigured verifies +// that skipping every unsupported strategy preserves the generic chain error. +func TestDefaultCredentials_GroupedChainExhaustionReturnsNoAuthConfigured(t *testing.T) { + unsupported := strategy{ + name: "pat", + configure: func(profiles.Profile) (auth.Credentials, error) { + return NewPATCredentials("dapi-abc") + }, + } + + creds := newTestChain([]strategy{unsupported}, profiles.Profile{GroupID: "group-id"}) + + _, err := creds.AuthHeaders(context.Background()) + if !errors.Is(err, ErrNoAuthConfigured) { + t.Fatalf("AuthHeaders() error = %v, want %v", err, ErrNoAuthConfigured) + } +} + +// TestDefaultCredentials_BuiltInUnsupportedStrategiesRejectGroup verifies that +// the built-in PAT and CLI strategies reject explicit grouped authentication. +func TestDefaultCredentials_BuiltInUnsupportedStrategiesRejectGroup(t *testing.T) { + testCases := []struct { + name string + authType string + profile profiles.Profile + }{ + { + name: "PAT", + authType: "pat", + profile: profiles.Profile{ + Host: testHost, + Token: "dapi-normal-access", + }, + }, + { + name: "Databricks CLI", + authType: "databricks-cli", + profile: profiles.Profile{ + Name: "DEFAULT", + Host: testHost, + DatabricksCLIPath: "/path/that/must/not/be/invoked", + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + profile := tc.profile + profile.AuthType = tc.authType + profile.GroupID = "group-id" + + creds := NewDefaultCredentials(DefaultCredentialsOptions{Profile: &profile}) + + _, err := creds.AuthHeaders(context.Background()) + if err == nil || !strings.Contains(err.Error(), "does not support group role assumption") { + t.Fatalf("AuthHeaders() error = %v", err) + } + }) + } +} + +// TestDefaultCredentials_DoesNotFallBackAfterSelectedProviderFails verifies +// that a token failure from the selected provider is returned without trying a +// later credential strategy. +func TestDefaultCredentials_DoesNotFallBackAfterSelectedProviderFails(t *testing.T) { + providerErr := errors.New("group assumption rejected") + fallbackCalls := 0 + failed := strategy{ + name: "oauth-m2m", + supportsGroupAssumption: true, + configure: func(profiles.Profile) (auth.Credentials, error) { + return auth.NewTokenCredentials("oauth-m2m", auth.TokenProviderFn( + func(context.Context) (*auth.Token, error) { return nil, providerErr }, + )), nil + }, + } + + fallback := strategy{ + name: "fallback", + supportsGroupAssumption: true, + configure: func(profiles.Profile) (auth.Credentials, error) { + fallbackCalls++ + return NewPATCredentials("dapi-fallback") + }, + } + + creds := newTestChain([]strategy{failed, fallback}, profiles.Profile{GroupID: "group-id"}) + + _, err := creds.AuthHeaders(context.Background()) + if !errors.Is(err, providerErr) { + t.Fatalf("AuthHeaders() error = %v, want %v", err, providerErr) + } + + if fallbackCalls != 0 { + t.Errorf("fallback configure calls = %d, want 0", fallbackCalls) + } +} + +func TestDefaultCredentials_GroupedStrategiesForwardGroup(t *testing.T) { + testCases := []struct { + name string + profile profiles.Profile + setEnv func(*testing.T) + wantName string + }{ + { + name: "OAuth M2M wins over PAT", + profile: profiles.Profile{ + Token: "dapi-normal-access", + ClientID: "client-id", + ClientSecret: "client-secret", + GroupID: "group-id", + }, + wantName: "oauth-m2m", + }, + { + name: "environment OIDC", + profile: profiles.Profile{ + ClientID: "client-id", + GroupID: "group-id", + Token: "dapi-normal-access", + }, + setEnv: func(t *testing.T) { + t.Setenv(defaultOIDCTokenEnv, "id-token") + }, + wantName: "env-oidc", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + isolateOIDCEnvironment(t) + if tc.setEnv != nil { + tc.setEnv(t) + } + + s := newFakeOIDCServer() + defer s.Close() + profile := tc.profile + profile.Host = s.server.URL + creds := NewDefaultCredentials(DefaultCredentialsOptions{Profile: &profile}) + + headers, err := creds.AuthHeaders(context.Background()) + if err != nil { + t.Fatalf("AuthHeaders() error = %v", err) + } + + want := []auth.Header{{Key: "Authorization", Value: "Bearer access-token"}} + if diff := cmp.Diff(want, headers); diff != "" { + t.Errorf("AuthHeaders() mismatch (-want +got):\n%s", diff) + } + + if got := creds.Name(); got != tc.wantName { + t.Errorf("Name() = %q, want %q", got, tc.wantName) + } + + if got, want := s.lastRequest.Get("assume_group"), "group-id"; got != want { + t.Errorf("assume_group = %q, want %q", got, want) + } + }) + } +} + func TestDefaultCredentials_Name(t *testing.T) { testCases := []struct { desc string diff --git a/auth/credentials/m2m.go b/auth/credentials/m2m.go index ac69a2d..6ddb2b2 100644 --- a/auth/credentials/m2m.go +++ b/auth/credentials/m2m.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "net/http" + "net/url" "sync/atomic" "github.com/databricks/sdk-go/auth" @@ -32,6 +33,10 @@ type M2MOptions struct { // "https://example.cloud.databricks.com"). Required. Host string + // GroupID is the ID of the group whose role is assumed by the issued token. + // When empty, no group role is assumed. + GroupID string + // Scopes overrides the OAuth scopes requested for the token. If empty, // defaults to ["all-apis"]. Scopes []string @@ -67,6 +72,7 @@ func NewM2MCredentials(opts M2MOptions) (auth.TokenProvider, error) { clientID: opts.ClientID, clientSecret: opts.ClientSecret, host: opts.Host, + groupID: opts.GroupID, scopes: scopes, httpClient: opts.HTTPClient, }, nil @@ -76,6 +82,7 @@ type m2mTokenProvider struct { clientID string clientSecret string host string + groupID string scopes []string httpClient *http.Client @@ -98,6 +105,9 @@ func (m *m2mTokenProvider) Token(ctx context.Context) (*auth.Token, error) { Scopes: m.scopes, AuthStyle: oauth2.AuthStyleInHeader, } + if m.groupID != "" { + cfg.EndpointParams = url.Values{"assume_group": {m.groupID}} + } ot, err := fetchToken(ctx, m.httpClient, cfg) if err != nil { return nil, fmt.Errorf("fetch token: %w", err) diff --git a/auth/credentials/m2m_test.go b/auth/credentials/m2m_test.go index 108d271..d0cd08c 100644 --- a/auth/credentials/m2m_test.go +++ b/auth/credentials/m2m_test.go @@ -13,6 +13,7 @@ import ( "time" "github.com/databricks/sdk-go/auth" + "github.com/databricks/sdk-go/core/apierr" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" ) @@ -70,60 +71,98 @@ type fakeOIDCServer struct { server *httptest.Server tokenCalls int32 lastRequest url.Values + requests []url.Values lastAuthUser string lastAuthPass string // Response overrides. - accessToken string tokenType string expiresIn int tokenStatus int // 0 means 200 discoveryBad bool + tokenPath string + // tokenValue makes the fake server's access token an explicit function of + // the request, allowing tests to expose differences between token forms. + tokenValue func(url.Values) string } func newFakeOIDCServer() *fakeOIDCServer { + return newFakeOIDCServerWithTokenPath("/oidc/v1/token") +} + +// newFakeOIDCServerWithTokenPath creates a discoverable fake OIDC server whose +// token endpoint uses the supplied path. +func newFakeOIDCServerWithTokenPath(tokenPath string) *fakeOIDCServer { f := &fakeOIDCServer{ - accessToken: "access-token", - tokenType: "Bearer", - expiresIn: 3600, + tokenType: "Bearer", + expiresIn: 3600, + tokenPath: tokenPath, + tokenValue: func(url.Values) string { return "access-token" }, } + mux := http.NewServeMux() mux.HandleFunc("/oidc/.well-known/oauth-authorization-server", func(w http.ResponseWriter, r *http.Request) { if f.discoveryBad { http.Error(w, "nope", http.StatusInternalServerError) return } + w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(map[string]string{ - "token_endpoint": f.server.URL + "/oidc/v1/token", + "token_endpoint": f.server.URL + f.tokenPath, }) }) - mux.HandleFunc("/oidc/v1/token", func(w http.ResponseWriter, r *http.Request) { + + mux.HandleFunc(tokenPath, func(w http.ResponseWriter, r *http.Request) { atomic.AddInt32(&f.tokenCalls, 1) + if err := r.ParseForm(); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } + f.lastRequest = r.PostForm + f.requests = append(f.requests, r.PostForm) f.lastAuthUser, f.lastAuthPass, _ = r.BasicAuth() if f.tokenStatus != 0 { http.Error(w, "failure", f.tokenStatus) return } + w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(map[string]any{ - "access_token": f.accessToken, + "access_token": f.tokenValue(r.PostForm), "token_type": f.tokenType, "expires_in": f.expiresIn, }) }) + f.server = httptest.NewServer(mux) + return f } func (f *fakeOIDCServer) Close() { f.server.Close() } +// newTestM2MProvider creates an M2M provider with the standard credentials +// shared by group-assumption token exchange tests. +func newTestM2MProvider(t *testing.T, server *fakeOIDCServer, groupID string) auth.TokenProvider { + t.Helper() + + provider, err := NewM2MCredentials(M2MOptions{ + ClientID: "client-id", + ClientSecret: "client-secret", + Host: server.server.URL, + GroupID: groupID, + }) + if err != nil { + t.Fatalf("NewM2MCredentials() error = %v", err) + } + + return provider +} + func TestM2M_Token_Success(t *testing.T) { s := newFakeOIDCServer() defer s.Close() @@ -163,6 +202,188 @@ func TestM2M_Token_Success(t *testing.T) { } } +// TestM2M_Token_AssumeGroup verifies that M2M token requests include the +// configured group and omit assume_group when no group is configured. +func TestM2M_Token_AssumeGroup(t *testing.T) { + testCases := []struct { + name string + groupID string + }{ + { + name: "normal", + }, + { + name: "group A", + groupID: "group-a", + }, + { + name: "group B", + groupID: "group-b", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + server := newFakeOIDCServer() + defer server.Close() + + provider := newTestM2MProvider(t, server, tc.groupID) + + // Repeated exchanges verify that the fixed provider configuration is + // retained after discovery has been cached. + for range 2 { + if _, err := provider.Token(context.Background()); err != nil { + t.Fatalf("Token() error = %v", err) + } + + wantForm := url.Values{ + "grant_type": {"client_credentials"}, + "scope": {"all-apis"}, + } + if tc.groupID != "" { + wantForm.Set("assume_group", tc.groupID) + } + + if diff := cmp.Diff(wantForm, server.lastRequest); diff != "" { + t.Errorf("token form mismatch (-want +got):\n%s", diff) + } + } + + if got, want := atomic.LoadInt32(&server.tokenCalls), int32(2); got != want { + t.Errorf("token calls = %d, want %d", got, want) + } + }) + } +} + +// TestM2M_Token_AssumeGroupForEveryEndpointType verifies that group assumption +// is sent to workspace and the shared account or unified token endpoint shape. +func TestM2M_Token_AssumeGroupForEveryEndpointType(t *testing.T) { + testCases := []struct { + name string + tokenPath string + }{ + { + name: "workspace", + tokenPath: "/oidc/v1/token", + }, + { + name: "account or unified", + tokenPath: "/oidc/accounts/account-id/v1/token", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + server := newFakeOIDCServerWithTokenPath(tc.tokenPath) + defer server.Close() + + provider := newTestM2MProvider(t, server, "group-id") + + if _, err := provider.Token(context.Background()); err != nil { + t.Fatalf("Token() error = %v", err) + } + + if got, want := server.lastRequest.Get("assume_group"), "group-id"; got != want { + t.Errorf("assume_group = %q, want %q", got, want) + } + }) + } +} + +// TestM2M_GroupCachesAreIsolated verifies that cached providers configured for +// different groups retain the token issued for their own group. +func TestM2M_GroupCachesAreIsolated(t *testing.T) { + server := newFakeOIDCServer() + defer server.Close() + + server.tokenValue = func(form url.Values) string { + if groupID := form.Get("assume_group"); groupID != "" { + return groupID + "-token" + } + return "normal-token" + } + + for _, groupID := range []string{"", "group-a", "group-b"} { + provider := newTestM2MProvider(t, server, groupID) + + cached := auth.NewCachedTokenProvider(provider, auth.WithAsyncRefresh(false)) + for range 2 { + token, err := cached.Token(context.Background()) + if err != nil { + t.Fatalf("Token() error = %v", err) + } + + want := "normal-token" + if groupID != "" { + want = groupID + "-token" + } + + if token.Value != want { + t.Errorf("Token().Value = %q, want %q", token.Value, want) + } + } + } + + if got, want := atomic.LoadInt32(&server.tokenCalls), int32(3); got != want { + t.Errorf("token calls = %d, want %d", got, want) + } +} + +// TestM2M_ExpiredCachedTokenRetainsGroup verifies that every refresh of an +// expired M2M token retains the configured group. +func TestM2M_ExpiredCachedTokenRetainsGroup(t *testing.T) { + server := newFakeOIDCServer() + defer server.Close() + + server.expiresIn = -1 + + provider := newTestM2MProvider(t, server, "group-id") + + cached := auth.NewCachedTokenProvider(provider, auth.WithAsyncRefresh(false)) + for range 2 { + if _, err := cached.Token(context.Background()); err != nil { + t.Fatalf("Token() error = %v", err) + } + } + + if got, want := atomic.LoadInt32(&server.tokenCalls), int32(2); got != want { + t.Fatalf("token calls = %d, want %d", got, want) + } + + for i, form := range server.requests { + if got, want := form.Get("assume_group"), "group-id"; got != want { + t.Errorf("request %d assume_group = %q, want %q", i, got, want) + } + } +} + +// TestM2M_Token_GroupRejectionIsNotRetried verifies that a rejected grouped +// token request is returned to the caller without another token request. +func TestM2M_Token_GroupRejectionIsNotRetried(t *testing.T) { + server := newFakeOIDCServer() + defer server.Close() + + server.tokenStatus = http.StatusForbidden + + provider := newTestM2MProvider(t, server, "group-id") + + _, err := provider.Token(context.Background()) + + var apiError *apierr.APIError + if !errors.As(err, &apiError) || apiError.HTTPStatusCode() != http.StatusForbidden { + t.Fatalf("Token() error = %v, want wrapped APIError with status %d", err, http.StatusForbidden) + } + + if got, want := atomic.LoadInt32(&server.tokenCalls), int32(1); got != want { + t.Errorf("token calls = %d, want %d", got, want) + } + + if got, want := server.lastRequest.Get("assume_group"), "group-id"; got != want { + t.Errorf("assume_group = %q, want %q", got, want) + } +} + func TestM2M_Token_CustomScopes(t *testing.T) { s := newFakeOIDCServer() defer s.Close() diff --git a/auth/go.mod b/auth/go.mod index f9620b3..4103ce4 100644 --- a/auth/go.mod +++ b/auth/go.mod @@ -6,7 +6,7 @@ replace github.com/databricks/sdk-go/core => ../core require ( github.com/databricks/databricks-sdk-go v0.92.0 - github.com/databricks/sdk-go/core v0.0.1-dev.1 + github.com/databricks/sdk-go/core v0.0.1-dev.2 github.com/google/go-cmp v0.7.0 golang.org/x/oauth2 v0.33.0 ) diff --git a/auth/internal/version.go b/auth/internal/version.go index 0d97015..b944181 100644 --- a/auth/internal/version.go +++ b/auth/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-auth" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/auth/oidc/tokensource.go b/auth/oidc/tokensource.go index f8beb7a..fd1be48 100644 --- a/auth/oidc/tokensource.go +++ b/auth/oidc/tokensource.go @@ -28,6 +28,10 @@ type DatabricksOIDCTokenProviderConfig struct { // Host is the host of the Databricks account or workspace. Host string + // GroupID is the ID of the group whose role is assumed by the exchanged + // token. When empty, no group role is assumed. + GroupID string + // TokenEndpointProvider returns the token endpoint for the Databricks OIDC // application. TokenEndpointProvider func(ctx context.Context) (*u2m.OAuthAuthorizationServer, error) @@ -86,6 +90,9 @@ func (w *databricksOIDCTokenProvider) Token(ctx context.Context) (*auth.Token, e "grant_type": {"urn:ietf:params:oauth:grant-type:token-exchange"}, }, } + if w.cfg.GroupID != "" { + c.EndpointParams.Set("assume_group", w.cfg.GroupID) + } token, err := c.Token(ctx) if err != nil { return nil, err diff --git a/auth/oidc/tokensource_test.go b/auth/oidc/tokensource_test.go index c88f2e4..cc44ccd 100644 --- a/auth/oidc/tokensource_test.go +++ b/auth/oidc/tokensource_test.go @@ -10,6 +10,7 @@ import ( "github.com/databricks/databricks-sdk-go/credentials/u2m" "github.com/databricks/databricks-sdk-go/httpclient/fixtures" + "github.com/databricks/sdk-go/auth" "github.com/google/go-cmp/cmp" "golang.org/x/oauth2" ) @@ -315,3 +316,241 @@ func TestDatabricksOidcTokenProvider(t *testing.T) { }) } } + +type countingRoundTripper struct { + transport http.RoundTripper + calls int +} + +// RoundTrip records how many token exchanges reach the underlying transport. +func (t *countingRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) { + t.calls++ + return t.transport.RoundTrip(r) +} + +// newTokenExchangeRequest returns the standard WIF token exchange form with +// the optional client and group identifiers used by a test scenario. +func newTokenExchangeRequest(clientID, groupID string) url.Values { + request := url.Values{ + "grant_type": {"urn:ietf:params:oauth:grant-type:token-exchange"}, + "scope": {"all-apis"}, + "subject_token": {"id-token"}, + "subject_token_type": {"urn:ietf:params:oauth:token-type:jwt"}, + } + if clientID != "" { + request.Set("client_id", clientID) + } + if groupID != "" { + request.Set("assume_group", groupID) + } + + return request +} + +// contextWithOAuthTransport routes OAuth requests through the supplied test +// transport instead of the default HTTP client. +func contextWithOAuthTransport(transport http.RoundTripper) context.Context { + return context.WithValue(context.Background(), oauth2.HTTPClient, &http.Client{ + Transport: transport, + }) +} + +// newTestDatabricksOIDCProvider supplies fixed external ID token plumbing so +// tests can focus on the Databricks token exchange. +func newTestDatabricksOIDCProvider(tokenEndpoint, clientID, groupID string) auth.TokenProvider { + return NewDatabricksOIDCTokenProvider(DatabricksOIDCTokenProviderConfig{ + ClientID: clientID, + Host: "https://host.com", + GroupID: groupID, + TokenEndpointProvider: func(context.Context) (*u2m.OAuthAuthorizationServer, error) { + return &u2m.OAuthAuthorizationServer{TokenEndpoint: tokenEndpoint}, nil + }, + IDTokenProvider: IDTokenProviderFn(func(context.Context, string) (*IDToken, error) { + return &IDToken{Value: "id-token"}, nil + }), + }) +} + +// TestDatabricksOIDCGroupCachesAreIsolated verifies that cached WIF providers +// configured for different groups retain the token issued for their own group. +func TestDatabricksOIDCGroupCachesAreIsolated(t *testing.T) { + testCases := []struct { + name string + groupID string + wantToken string + }{ + { + name: "no group", + wantToken: "normal-token", + }, + { + name: "group A", + groupID: "group-a", + wantToken: "group-a-token", + }, + { + name: "group B", + groupID: "group-b", + wantToken: "group-b-token", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + transport := &countingRoundTripper{ + transport: fixtures.MappingTransport{ + "POST /oidc/v1/token": { + Status: http.StatusOK, + ExpectedRequest: newTokenExchangeRequest("client-id", tc.groupID), + Response: map[string]any{ + "access_token": tc.wantToken, + "token_type": "Bearer", + "expires_in": 3600, + }, + }, + }, + } + ctx := contextWithOAuthTransport(transport) + provider := newTestDatabricksOIDCProvider( + "https://host.com/oidc/v1/token", + "client-id", + tc.groupID, + ) + + cached := auth.NewCachedTokenProvider(provider, auth.WithAsyncRefresh(false)) + for range 2 { + token, err := cached.Token(ctx) + if err != nil { + t.Fatalf("Token() error = %v", err) + } + + if token.Value != tc.wantToken { + t.Errorf("Token().Value = %q, want %q", token.Value, tc.wantToken) + } + } + + if got, want := transport.calls, 1; got != want { + t.Errorf("token exchanges = %d, want %d", got, want) + } + }) + } +} + +// TestDatabricksOIDCAssumeGroupForEveryEndpointType verifies that WIF sends +// group assumption to workspace, shared account or unified, and account-wide +// exchanges. +func TestDatabricksOIDCAssumeGroupForEveryEndpointType(t *testing.T) { + testCases := []struct { + name string + tokenPath string + clientID string + }{ + { + name: "workspace", + tokenPath: "/oidc/v1/token", + clientID: "client-id", + }, + { + name: "account or unified", + tokenPath: "/oidc/accounts/account-id/v1/token", + clientID: "client-id", + }, + { + name: "account-wide", + tokenPath: "/oidc/accounts/account-id/v1/token", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + transport := fixtures.MappingTransport{ + "POST " + tc.tokenPath: { + Status: http.StatusOK, + ExpectedRequest: newTokenExchangeRequest(tc.clientID, "group-id"), + Response: map[string]any{ + "access_token": "access-token", + "token_type": "Bearer", + "expires_in": 3600, + }, + }, + } + ctx := contextWithOAuthTransport(transport) + provider := newTestDatabricksOIDCProvider( + "https://host.com"+tc.tokenPath, + tc.clientID, + "group-id", + ) + + if _, err := provider.Token(ctx); err != nil { + t.Fatalf("Token() error = %v", err) + } + }) + } +} + +// TestDatabricksOIDCGroupRejectionIsNotRetried verifies that a rejected grouped +// exchange is returned to the caller without another token request. +func TestDatabricksOIDCGroupRejectionIsNotRetried(t *testing.T) { + transport := &countingRoundTripper{ + transport: fixtures.MappingTransport{ + "POST /oidc/v1/token": { + Status: http.StatusBadRequest, + ExpectedRequest: newTokenExchangeRequest("client-id", "group-id"), + Response: map[string]string{ + "error": "invalid_request", + "error_description": "assume_group is not supported", + }, + }, + }, + } + ctx := contextWithOAuthTransport(transport) + provider := newTestDatabricksOIDCProvider( + "https://host.com/oidc/v1/token", + "client-id", + "group-id", + ) + + _, err := provider.Token(ctx) + if err == nil || !strings.Contains(err.Error(), "invalid_request") || !strings.Contains(err.Error(), "assume_group is not supported") { + t.Fatalf("Token() error = %v", err) + } + + if got, want := transport.calls, 1; got != want { + t.Errorf("token requests = %d, want %d", got, want) + } +} + +// TestDatabricksOIDCExpiredTokenRetainsGroup verifies that every refresh of an +// expired WIF token retains the configured group. +func TestDatabricksOIDCExpiredTokenRetainsGroup(t *testing.T) { + transport := &countingRoundTripper{ + transport: fixtures.MappingTransport{ + "POST /oidc/v1/token": { + Status: http.StatusOK, + ExpectedRequest: newTokenExchangeRequest("client-id", "group-id"), + Response: map[string]any{ + "access_token": "expired-token", + "token_type": "Bearer", + "expires_in": -1, + }, + }, + }, + } + ctx := contextWithOAuthTransport(transport) + provider := newTestDatabricksOIDCProvider( + "https://host.com/oidc/v1/token", + "client-id", + "group-id", + ) + + cached := auth.NewCachedTokenProvider(provider, auth.WithAsyncRefresh(false)) + for range 2 { + if _, err := cached.Token(ctx); err != nil { + t.Fatalf("Token() error = %v", err) + } + } + + if got, want := transport.calls, 2; got != want { + t.Fatalf("token exchanges = %d, want %d", got, want) + } +} diff --git a/authentication/CHANGELOG.md b/authentication/CHANGELOG.md index 6224c04..19f237c 100644 --- a/authentication/CHANGELOG.md +++ b/authentication/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/authentication/go.mod b/authentication/go.mod index 2b58a4a..a6adf69 100644 --- a/authentication/go.mod +++ b/authentication/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/authentication/internal/version.go b/authentication/internal/version.go index 2134368..ef9e9e1 100644 --- a/authentication/internal/version.go +++ b/authentication/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-authentication" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/authentication/v1/client.go b/authentication/v1/client.go old mode 100755 new mode 100644 index 385c621..a6549e8 --- a/authentication/v1/client.go +++ b/authentication/v1/client.go @@ -76,8 +76,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Create account federation policy. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateAccountFederationPolicy(ctx context.Context, req *CreateAccountFederationPolicyRequest, opts ...call.Option) (*FederationPolicy, error) { - wireReq, err := createAccountFederationPolicyRequestToWire(req) +func (c *internalClient) CreateAccountFederationPolicy(ctx context.Context, req CreateAccountFederationPolicyRequest, opts ...call.Option) (*FederationPolicy, error) { + wireReq, err := createAccountFederationPolicyRequestToWire(&req) if err != nil { return nil, err } @@ -154,8 +154,8 @@ func (c *internalClient) CreateAccountFederationPolicy(ctx context.Context, req // Create account federation policy. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateServicePrincipalFederationPolicy(ctx context.Context, req *CreateServicePrincipalFederationPolicyRequest, opts ...call.Option) (*FederationPolicy, error) { - wireReq, err := createServicePrincipalFederationPolicyRequestToWire(req) +func (c *internalClient) CreateServicePrincipalFederationPolicy(ctx context.Context, req CreateServicePrincipalFederationPolicyRequest, opts ...call.Option) (*FederationPolicy, error) { + wireReq, err := createServicePrincipalFederationPolicyRequestToWire(&req) if err != nil { return nil, err } @@ -179,7 +179,11 @@ func (c *internalClient) CreateServicePrincipalFederationPolicy(ctx context.Cont pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/servicePrincipals/") - pb.singleSegment(*req.ServicePrincipalId) + if req.ServicePrincipalId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ServicePrincipalId) + } pb.literal("/federationPolicies") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -231,8 +235,8 @@ func (c *internalClient) CreateServicePrincipalFederationPolicy(ctx context.Cont // Delete account federation policy. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteAccountFederationPolicy(ctx context.Context, req *DeleteAccountFederationPolicyRequest, opts ...call.Option) error { - wireReq, err := deleteAccountFederationPolicyRequestToWire(req) +func (c *internalClient) DeleteAccountFederationPolicy(ctx context.Context, req DeleteAccountFederationPolicyRequest, opts ...call.Option) error { + wireReq, err := deleteAccountFederationPolicyRequestToWire(&req) if err != nil { return err } @@ -252,7 +256,11 @@ func (c *internalClient) DeleteAccountFederationPolicy(ctx context.Context, req pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/federationPolicies/") - pb.singleSegment(*req.PolicyId) + if req.PolicyId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PolicyId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "service_principal_id", wireReq.ServicePrincipalId); err != nil { @@ -293,7 +301,7 @@ func (c *internalClient) DeleteAccountFederationPolicy(ctx context.Context, req // Delete account federation policy. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteServicePrincipalFederationPolicy(ctx context.Context, req *DeleteServicePrincipalFederationPolicyRequest, opts ...call.Option) error { +func (c *internalClient) DeleteServicePrincipalFederationPolicy(ctx context.Context, req DeleteServicePrincipalFederationPolicyRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -310,9 +318,17 @@ func (c *internalClient) DeleteServicePrincipalFederationPolicy(ctx context.Cont pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/servicePrincipals/") - pb.singleSegment(*req.ServicePrincipalId) + if req.ServicePrincipalId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ServicePrincipalId) + } pb.literal("/federationPolicies/") - pb.singleSegment(*req.PolicyId) + if req.PolicyId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PolicyId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -350,8 +366,8 @@ func (c *internalClient) DeleteServicePrincipalFederationPolicy(ctx context.Cont // Get account federation policy. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetAccountFederationPolicy(ctx context.Context, req *GetAccountFederationPolicyRequest, opts ...call.Option) (*FederationPolicy, error) { - wireReq, err := getAccountFederationPolicyRequestToWire(req) +func (c *internalClient) GetAccountFederationPolicy(ctx context.Context, req GetAccountFederationPolicyRequest, opts ...call.Option) (*FederationPolicy, error) { + wireReq, err := getAccountFederationPolicyRequestToWire(&req) if err != nil { return nil, err } @@ -371,7 +387,11 @@ func (c *internalClient) GetAccountFederationPolicy(ctx context.Context, req *Ge pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/federationPolicies/") - pb.singleSegment(*req.PolicyId) + if req.PolicyId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PolicyId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "service_principal_id", wireReq.ServicePrincipalId); err != nil { @@ -421,7 +441,7 @@ func (c *internalClient) GetAccountFederationPolicy(ctx context.Context, req *Ge // Get account federation policy. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetServicePrincipalFederationPolicy(ctx context.Context, req *GetServicePrincipalFederationPolicyRequest, opts ...call.Option) (*FederationPolicy, error) { +func (c *internalClient) GetServicePrincipalFederationPolicy(ctx context.Context, req GetServicePrincipalFederationPolicyRequest, opts ...call.Option) (*FederationPolicy, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -438,9 +458,17 @@ func (c *internalClient) GetServicePrincipalFederationPolicy(ctx context.Context pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/servicePrincipals/") - pb.singleSegment(*req.ServicePrincipalId) + if req.ServicePrincipalId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ServicePrincipalId) + } pb.literal("/federationPolicies/") - pb.singleSegment(*req.PolicyId) + if req.PolicyId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PolicyId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -487,8 +515,8 @@ func (c *internalClient) GetServicePrincipalFederationPolicy(ctx context.Context // List account federation policies. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListAccountFederationPolicies(ctx context.Context, req *ListAccountFederationPoliciesRequest, opts ...call.Option) (*ListFederationPoliciesResponse, error) { - wireReq, err := listAccountFederationPoliciesRequestToWire(req) +func (c *internalClient) ListAccountFederationPolicies(ctx context.Context, req ListAccountFederationPoliciesRequest, opts ...call.Option) (*ListFederationPoliciesResponse, error) { + wireReq, err := listAccountFederationPoliciesRequestToWire(&req) if err != nil { return nil, err } @@ -566,7 +594,7 @@ func (c *internalClient) ListAccountFederationPolicies(ctx context.Context, req // // For example: // -// for item, err := range c.ListAccountFederationPoliciesIter(ctx, &ListAccountFederationPoliciesRequest{}) { +// for item, err := range c.ListAccountFederationPoliciesIter(ctx, ListAccountFederationPoliciesRequest{}) { // if err != nil { // return err // } @@ -578,16 +606,13 @@ func (c *internalClient) ListAccountFederationPolicies(ctx context.Context, req // // Callers who need custom pagination logic should use // ListAccountFederationPolicies directly. -func (c *internalClient) ListAccountFederationPoliciesIter(ctx context.Context, req *ListAccountFederationPoliciesRequest, opts ...call.Option) iter.Seq2[*FederationPolicy, error] { +func (c *internalClient) ListAccountFederationPoliciesIter(ctx context.Context, req ListAccountFederationPoliciesRequest, opts ...call.Option) iter.Seq2[*FederationPolicy, error] { return func(yield func(*FederationPolicy, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListAccountFederationPoliciesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListAccountFederationPolicies(ctx, &pageReq, opts...) + resp, err := c.ListAccountFederationPolicies(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -607,8 +632,8 @@ func (c *internalClient) ListAccountFederationPoliciesIter(ctx context.Context, // List account federation policies. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListServicePrincipalFederationPolicies(ctx context.Context, req *ListServicePrincipalFederationPoliciesRequest, opts ...call.Option) (*ListFederationPoliciesResponse, error) { - wireReq, err := listServicePrincipalFederationPoliciesRequestToWire(req) +func (c *internalClient) ListServicePrincipalFederationPolicies(ctx context.Context, req ListServicePrincipalFederationPoliciesRequest, opts ...call.Option) (*ListFederationPoliciesResponse, error) { + wireReq, err := listServicePrincipalFederationPoliciesRequestToWire(&req) if err != nil { return nil, err } @@ -628,7 +653,11 @@ func (c *internalClient) ListServicePrincipalFederationPolicies(ctx context.Cont pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/servicePrincipals/") - pb.singleSegment(*req.ServicePrincipalId) + if req.ServicePrincipalId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ServicePrincipalId) + } pb.literal("/federationPolicies") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -685,7 +714,7 @@ func (c *internalClient) ListServicePrincipalFederationPolicies(ctx context.Cont // // For example: // -// for item, err := range c.ListServicePrincipalFederationPoliciesIter(ctx, &ListServicePrincipalFederationPoliciesRequest{}) { +// for item, err := range c.ListServicePrincipalFederationPoliciesIter(ctx, ListServicePrincipalFederationPoliciesRequest{}) { // if err != nil { // return err // } @@ -697,16 +726,13 @@ func (c *internalClient) ListServicePrincipalFederationPolicies(ctx context.Cont // // Callers who need custom pagination logic should use // ListServicePrincipalFederationPolicies directly. -func (c *internalClient) ListServicePrincipalFederationPoliciesIter(ctx context.Context, req *ListServicePrincipalFederationPoliciesRequest, opts ...call.Option) iter.Seq2[*FederationPolicy, error] { +func (c *internalClient) ListServicePrincipalFederationPoliciesIter(ctx context.Context, req ListServicePrincipalFederationPoliciesRequest, opts ...call.Option) iter.Seq2[*FederationPolicy, error] { return func(yield func(*FederationPolicy, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListServicePrincipalFederationPoliciesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListServicePrincipalFederationPolicies(ctx, &pageReq, opts...) + resp, err := c.ListServicePrincipalFederationPolicies(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -726,8 +752,8 @@ func (c *internalClient) ListServicePrincipalFederationPoliciesIter(ctx context. // Update account federation policy. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdateAccountFederationPolicy(ctx context.Context, req *UpdateAccountFederationPolicyRequest, opts ...call.Option) (*FederationPolicy, error) { - wireReq, err := updateAccountFederationPolicyRequestToWire(req) +func (c *internalClient) UpdateAccountFederationPolicy(ctx context.Context, req UpdateAccountFederationPolicyRequest, opts ...call.Option) (*FederationPolicy, error) { + wireReq, err := updateAccountFederationPolicyRequestToWire(&req) if err != nil { return nil, err } @@ -751,7 +777,11 @@ func (c *internalClient) UpdateAccountFederationPolicy(ctx context.Context, req pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/federationPolicies/") - pb.singleSegment(*req.PolicyId) + if req.PolicyId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PolicyId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "service_principal_id", wireReq.ServicePrincipalId); err != nil { @@ -805,8 +835,8 @@ func (c *internalClient) UpdateAccountFederationPolicy(ctx context.Context, req // Update account federation policy. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdateServicePrincipalFederationPolicy(ctx context.Context, req *UpdateServicePrincipalFederationPolicyRequest, opts ...call.Option) (*FederationPolicy, error) { - wireReq, err := updateServicePrincipalFederationPolicyRequestToWire(req) +func (c *internalClient) UpdateServicePrincipalFederationPolicy(ctx context.Context, req UpdateServicePrincipalFederationPolicyRequest, opts ...call.Option) (*FederationPolicy, error) { + wireReq, err := updateServicePrincipalFederationPolicyRequestToWire(&req) if err != nil { return nil, err } @@ -830,9 +860,17 @@ func (c *internalClient) UpdateServicePrincipalFederationPolicy(ctx context.Cont pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/servicePrincipals/") - pb.singleSegment(*req.ServicePrincipalId) + if req.ServicePrincipalId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ServicePrincipalId) + } pb.literal("/federationPolicies/") - pb.singleSegment(*req.PolicyId) + if req.PolicyId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PolicyId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -883,8 +921,8 @@ func (c *internalClient) UpdateServicePrincipalFederationPolicy(ctx context.Cont // Create a secret for the given service principal. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateServicePrincipalSecret(ctx context.Context, req *CreateServicePrincipalSecretRequest, opts ...call.Option) (*CreateServicePrincipalSecretResponse, error) { - wireReq, err := createServicePrincipalSecretRequestToWire(req) +func (c *internalClient) CreateServicePrincipalSecret(ctx context.Context, req CreateServicePrincipalSecretRequest, opts ...call.Option) (*CreateServicePrincipalSecretResponse, error) { + wireReq, err := createServicePrincipalSecretRequestToWire(&req) if err != nil { return nil, err } @@ -908,7 +946,11 @@ func (c *internalClient) CreateServicePrincipalSecret(ctx context.Context, req * pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/servicePrincipals/") - pb.singleSegment(*req.ServicePrincipal) + if req.ServicePrincipal == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ServicePrincipal) + } pb.literal("/credentials/secrets") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -956,8 +998,8 @@ func (c *internalClient) CreateServicePrincipalSecret(ctx context.Context, req * } // Create a secret for the given service principal. -func (c *internalClient) CreateServicePrincipalSecretProxy(ctx context.Context, req *CreateServicePrincipalSecretRequest, opts ...call.Option) (*CreateServicePrincipalSecretResponse, error) { - wireReq, err := createServicePrincipalSecretRequestToWire(req) +func (c *internalClient) CreateServicePrincipalSecretProxy(ctx context.Context, req CreateServicePrincipalSecretRequest, opts ...call.Option) (*CreateServicePrincipalSecretResponse, error) { + wireReq, err := createServicePrincipalSecretRequestToWire(&req) if err != nil { return nil, err } @@ -978,7 +1020,11 @@ func (c *internalClient) CreateServicePrincipalSecretProxy(ctx context.Context, } pb := pathBuilder{} pb.literal("/api/2.0/accounts/servicePrincipals/") - pb.singleSegment(*req.ServicePrincipal) + if req.ServicePrincipal == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ServicePrincipal) + } pb.literal("/credentials/secrets") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1027,7 +1073,7 @@ func (c *internalClient) CreateServicePrincipalSecretProxy(ctx context.Context, // Delete a secret from the given service principal. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteServicePrincipalSecret(ctx context.Context, req *DeleteServicePrincipalSecretRequest, opts ...call.Option) (*DeleteServicePrincipalSecretResponse, error) { +func (c *internalClient) DeleteServicePrincipalSecret(ctx context.Context, req DeleteServicePrincipalSecretRequest, opts ...call.Option) (*DeleteServicePrincipalSecretResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1044,9 +1090,17 @@ func (c *internalClient) DeleteServicePrincipalSecret(ctx context.Context, req * pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/servicePrincipals/") - pb.singleSegment(*req.ServicePrincipal) + if req.ServicePrincipal == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ServicePrincipal) + } pb.literal("/credentials/secrets/") - pb.singleSegment(*req.SecretId) + if req.SecretId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SecretId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1086,8 +1140,8 @@ func (c *internalClient) DeleteServicePrincipalSecret(ctx context.Context, req * } // Delete a secret from the given service principal. -func (c *internalClient) DeleteServicePrincipalSecretProxy(ctx context.Context, req *DeleteServicePrincipalSecretRequest, opts ...call.Option) (*DeleteServicePrincipalSecretResponse, error) { - wireReq, err := deleteServicePrincipalSecretRequestToWire(req) +func (c *internalClient) DeleteServicePrincipalSecretProxy(ctx context.Context, req DeleteServicePrincipalSecretRequest, opts ...call.Option) (*DeleteServicePrincipalSecretResponse, error) { + wireReq, err := deleteServicePrincipalSecretRequestToWire(&req) if err != nil { return nil, err } @@ -1104,9 +1158,17 @@ func (c *internalClient) DeleteServicePrincipalSecretProxy(ctx context.Context, } pb := pathBuilder{} pb.literal("/api/2.0/accounts/servicePrincipals/") - pb.singleSegment(*req.ServicePrincipal) + if req.ServicePrincipal == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ServicePrincipal) + } pb.literal("/credentials/secrets/") - pb.singleSegment(*req.SecretId) + if req.SecretId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SecretId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "account_id", wireReq.AccountId); err != nil { @@ -1152,8 +1214,8 @@ func (c *internalClient) DeleteServicePrincipalSecretProxy(ctx context.Context, // only returns information about the secrets themselves and does not include // the secret values. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListServicePrincipalSecrets(ctx context.Context, req *ListServicePrincipalSecretsRequest, opts ...call.Option) (*ListServicePrincipalSecretsResponse, error) { - wireReq, err := listServicePrincipalSecretsRequestToWire(req) +func (c *internalClient) ListServicePrincipalSecrets(ctx context.Context, req ListServicePrincipalSecretsRequest, opts ...call.Option) (*ListServicePrincipalSecretsResponse, error) { + wireReq, err := listServicePrincipalSecretsRequestToWire(&req) if err != nil { return nil, err } @@ -1173,7 +1235,11 @@ func (c *internalClient) ListServicePrincipalSecrets(ctx context.Context, req *L pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/servicePrincipals/") - pb.singleSegment(*req.ServicePrincipal) + if req.ServicePrincipal == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ServicePrincipal) + } pb.literal("/credentials/secrets") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1230,7 +1296,7 @@ func (c *internalClient) ListServicePrincipalSecrets(ctx context.Context, req *L // // For example: // -// for item, err := range c.ListServicePrincipalSecretsIter(ctx, &ListServicePrincipalSecretsRequest{}) { +// for item, err := range c.ListServicePrincipalSecretsIter(ctx, ListServicePrincipalSecretsRequest{}) { // if err != nil { // return err // } @@ -1242,16 +1308,13 @@ func (c *internalClient) ListServicePrincipalSecrets(ctx context.Context, req *L // // Callers who need custom pagination logic should use // ListServicePrincipalSecrets directly. -func (c *internalClient) ListServicePrincipalSecretsIter(ctx context.Context, req *ListServicePrincipalSecretsRequest, opts ...call.Option) iter.Seq2[*ServicePrincipalSecret, error] { +func (c *internalClient) ListServicePrincipalSecretsIter(ctx context.Context, req ListServicePrincipalSecretsRequest, opts ...call.Option) iter.Seq2[*ServicePrincipalSecret, error] { return func(yield func(*ServicePrincipalSecret, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListServicePrincipalSecretsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListServicePrincipalSecrets(ctx, &pageReq, opts...) + resp, err := c.ListServicePrincipalSecrets(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1272,8 +1335,8 @@ func (c *internalClient) ListServicePrincipalSecretsIter(ctx context.Context, re // List all secrets associated with the given service principal. This operation // only returns information about the secrets themselves and does not include // the secret values. -func (c *internalClient) ListServicePrincipalSecretsProxy(ctx context.Context, req *ListServicePrincipalSecretsRequest, opts ...call.Option) (*ListServicePrincipalSecretsResponse, error) { - wireReq, err := listServicePrincipalSecretsRequestToWire(req) +func (c *internalClient) ListServicePrincipalSecretsProxy(ctx context.Context, req ListServicePrincipalSecretsRequest, opts ...call.Option) (*ListServicePrincipalSecretsResponse, error) { + wireReq, err := listServicePrincipalSecretsRequestToWire(&req) if err != nil { return nil, err } @@ -1290,7 +1353,11 @@ func (c *internalClient) ListServicePrincipalSecretsProxy(ctx context.Context, r } pb := pathBuilder{} pb.literal("/api/2.0/accounts/servicePrincipals/") - pb.singleSegment(*req.ServicePrincipal) + if req.ServicePrincipal == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ServicePrincipal) + } pb.literal("/credentials/secrets") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1350,7 +1417,7 @@ func (c *internalClient) ListServicePrincipalSecretsProxy(ctx context.Context, r // // For example: // -// for item, err := range c.ListServicePrincipalSecretsProxyIter(ctx, &ListServicePrincipalSecretsRequest{}) { +// for item, err := range c.ListServicePrincipalSecretsProxyIter(ctx, ListServicePrincipalSecretsRequest{}) { // if err != nil { // return err // } @@ -1362,16 +1429,13 @@ func (c *internalClient) ListServicePrincipalSecretsProxy(ctx context.Context, r // // Callers who need custom pagination logic should use // ListServicePrincipalSecretsProxy directly. -func (c *internalClient) ListServicePrincipalSecretsProxyIter(ctx context.Context, req *ListServicePrincipalSecretsRequest, opts ...call.Option) iter.Seq2[*ServicePrincipalSecret, error] { +func (c *internalClient) ListServicePrincipalSecretsProxyIter(ctx context.Context, req ListServicePrincipalSecretsRequest, opts ...call.Option) iter.Seq2[*ServicePrincipalSecret, error] { return func(yield func(*ServicePrincipalSecret, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListServicePrincipalSecretsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListServicePrincipalSecretsProxy(ctx, &pageReq, opts...) + resp, err := c.ListServicePrincipalSecretsProxy(ctx, pageReq, opts...) if err != nil { yield(nil, err) return diff --git a/authentication/v1/genhelper.go b/authentication/v1/genhelper.go old mode 100755 new mode 100644 index 30422df..8d959e7 --- a/authentication/v1/genhelper.go +++ b/authentication/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/authentication/v1/wire.go b/authentication/v1/wire.go old mode 100755 new mode 100644 index 9ed6a8f..4e524fc --- a/authentication/v1/wire.go +++ b/authentication/v1/wire.go @@ -3,11 +3,57 @@ package authentication import ( + "bytes" + "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + func fieldMaskToWire[T any](mask *types.FieldMask[T]) *string { if mask == nil { return nil @@ -18,7 +64,7 @@ func fieldMaskToWire[T any](mask *types.FieldMask[T]) *string { type createAccountFederationPolicyRequestWire struct { AccountId *string `json:"account_id,omitempty"` - ServicePrincipalId *int64 `json:"service_principal_id,omitempty"` + ServicePrincipalId *wireInt64 `json:"service_principal_id,omitempty"` PolicyId *string `json:"policy_id,omitempty"` Policy *federationPolicyWire `json:"policy,omitempty"` } @@ -27,13 +73,17 @@ func createAccountFederationPolicyRequestToWire(v *CreateAccountFederationPolicy if v == nil { return nil, nil } + servicePrincipalIdWireValue, err := int64ToWire(v.ServicePrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateAccountFederationPolicyRequest.ServicePrincipalId", err) + } policyWireValue, err := federationPolicyToWire(v.Policy) if err != nil { return nil, fmt.Errorf("%s: %w", "CreateAccountFederationPolicyRequest.Policy", err) } return &createAccountFederationPolicyRequestWire{ AccountId: v.AccountId, - ServicePrincipalId: v.ServicePrincipalId, + ServicePrincipalId: servicePrincipalIdWireValue, PolicyId: v.PolicyId, Policy: policyWireValue, }, nil @@ -41,7 +91,7 @@ func createAccountFederationPolicyRequestToWire(v *CreateAccountFederationPolicy type createServicePrincipalFederationPolicyRequestWire struct { AccountId *string `json:"account_id,omitempty"` - ServicePrincipalId *int64 `json:"service_principal_id,omitempty"` + ServicePrincipalId *wireInt64 `json:"service_principal_id,omitempty"` PolicyId *string `json:"policy_id,omitempty"` Policy *federationPolicyWire `json:"policy,omitempty"` } @@ -50,13 +100,17 @@ func createServicePrincipalFederationPolicyRequestToWire(v *CreateServicePrincip if v == nil { return nil, nil } + servicePrincipalIdWireValue, err := int64ToWire(v.ServicePrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateServicePrincipalFederationPolicyRequest.ServicePrincipalId", err) + } policyWireValue, err := federationPolicyToWire(v.Policy) if err != nil { return nil, fmt.Errorf("%s: %w", "CreateServicePrincipalFederationPolicyRequest.Policy", err) } return &createServicePrincipalFederationPolicyRequestWire{ AccountId: v.AccountId, - ServicePrincipalId: v.ServicePrincipalId, + ServicePrincipalId: servicePrincipalIdWireValue, PolicyId: v.PolicyId, Policy: policyWireValue, }, nil @@ -105,18 +159,22 @@ func createServicePrincipalSecretResponseFromWire(w *createServicePrincipalSecre } type deleteAccountFederationPolicyRequestWire struct { - AccountId *string `json:"account_id,omitempty"` - ServicePrincipalId *int64 `json:"service_principal_id,omitempty"` - PolicyId *string `json:"policy_id,omitempty"` + AccountId *string `json:"account_id,omitempty"` + ServicePrincipalId *wireInt64 `json:"service_principal_id,omitempty"` + PolicyId *string `json:"policy_id,omitempty"` } func deleteAccountFederationPolicyRequestToWire(v *DeleteAccountFederationPolicyRequest) (*deleteAccountFederationPolicyRequestWire, error) { if v == nil { return nil, nil } + servicePrincipalIdWireValue, err := int64ToWire(v.ServicePrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DeleteAccountFederationPolicyRequest.ServicePrincipalId", err) + } return &deleteAccountFederationPolicyRequestWire{ AccountId: v.AccountId, - ServicePrincipalId: v.ServicePrincipalId, + ServicePrincipalId: servicePrincipalIdWireValue, PolicyId: v.PolicyId, }, nil } @@ -145,7 +203,7 @@ type federationPolicyWire struct { CreateTime *types.Time `json:"create_time,omitempty"` UpdateTime *types.Time `json:"update_time,omitempty"` Uid *string `json:"uid,omitempty"` - ServicePrincipalId *int64 `json:"service_principal_id,omitempty"` + ServicePrincipalId *wireInt64 `json:"service_principal_id,omitempty"` PolicyId *string `json:"policy_id,omitempty"` } @@ -153,6 +211,10 @@ func federationPolicyToWire(v *FederationPolicy) (*federationPolicyWire, error) if v == nil { return nil, nil } + servicePrincipalIdWireValue, err := int64ToWire(v.ServicePrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FederationPolicy.ServicePrincipalId", err) + } var policyOidcPolicyWire *oidcFederationPolicyWire switch value := v.Policy.(type) { case nil: @@ -174,7 +236,7 @@ func federationPolicyToWire(v *FederationPolicy) (*federationPolicyWire, error) CreateTime: v.CreateTime, UpdateTime: v.UpdateTime, Uid: v.Uid, - ServicePrincipalId: v.ServicePrincipalId, + ServicePrincipalId: servicePrincipalIdWireValue, PolicyId: v.PolicyId, }, nil } @@ -190,6 +252,10 @@ func federationPolicyFromWire(w *federationPolicyWire) (*FederationPolicy, error if policyMembers > 1 { return nil, fmt.Errorf("%s: multiple oneof members set", "FederationPolicy.Policy") } + servicePrincipalIdPublicValue, err := int64FromWire(w.ServicePrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FederationPolicy.ServicePrincipalId", err) + } var policySelection isFederationPolicy_Policy switch { case w.OidcPolicy != nil: @@ -205,43 +271,51 @@ func federationPolicyFromWire(w *federationPolicyWire) (*FederationPolicy, error CreateTime: w.CreateTime, UpdateTime: w.UpdateTime, Uid: w.Uid, - ServicePrincipalId: w.ServicePrincipalId, + ServicePrincipalId: servicePrincipalIdPublicValue, PolicyId: w.PolicyId, Policy: policySelection, }, nil } type getAccountFederationPolicyRequestWire struct { - AccountId *string `json:"account_id,omitempty"` - ServicePrincipalId *int64 `json:"service_principal_id,omitempty"` - PolicyId *string `json:"policy_id,omitempty"` + AccountId *string `json:"account_id,omitempty"` + ServicePrincipalId *wireInt64 `json:"service_principal_id,omitempty"` + PolicyId *string `json:"policy_id,omitempty"` } func getAccountFederationPolicyRequestToWire(v *GetAccountFederationPolicyRequest) (*getAccountFederationPolicyRequestWire, error) { if v == nil { return nil, nil } + servicePrincipalIdWireValue, err := int64ToWire(v.ServicePrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetAccountFederationPolicyRequest.ServicePrincipalId", err) + } return &getAccountFederationPolicyRequestWire{ AccountId: v.AccountId, - ServicePrincipalId: v.ServicePrincipalId, + ServicePrincipalId: servicePrincipalIdWireValue, PolicyId: v.PolicyId, }, nil } type listAccountFederationPoliciesRequestWire struct { - AccountId *string `json:"account_id,omitempty"` - ServicePrincipalId *int64 `json:"service_principal_id,omitempty"` - PageSize *int `json:"page_size,omitempty"` - PageToken *string `json:"page_token,omitempty"` + AccountId *string `json:"account_id,omitempty"` + ServicePrincipalId *wireInt64 `json:"service_principal_id,omitempty"` + PageSize *int `json:"page_size,omitempty"` + PageToken *string `json:"page_token,omitempty"` } func listAccountFederationPoliciesRequestToWire(v *ListAccountFederationPoliciesRequest) (*listAccountFederationPoliciesRequestWire, error) { if v == nil { return nil, nil } + servicePrincipalIdWireValue, err := int64ToWire(v.ServicePrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListAccountFederationPoliciesRequest.ServicePrincipalId", err) + } return &listAccountFederationPoliciesRequestWire{ AccountId: v.AccountId, - ServicePrincipalId: v.ServicePrincipalId, + ServicePrincipalId: servicePrincipalIdWireValue, PageSize: v.PageSize, PageToken: v.PageToken, }, nil @@ -267,19 +341,23 @@ func listFederationPoliciesResponseFromWire(w *listFederationPoliciesResponseWir } type listServicePrincipalFederationPoliciesRequestWire struct { - AccountId *string `json:"account_id,omitempty"` - ServicePrincipalId *int64 `json:"service_principal_id,omitempty"` - PageSize *int `json:"page_size,omitempty"` - PageToken *string `json:"page_token,omitempty"` + AccountId *string `json:"account_id,omitempty"` + ServicePrincipalId *wireInt64 `json:"service_principal_id,omitempty"` + PageSize *int `json:"page_size,omitempty"` + PageToken *string `json:"page_token,omitempty"` } func listServicePrincipalFederationPoliciesRequestToWire(v *ListServicePrincipalFederationPoliciesRequest) (*listServicePrincipalFederationPoliciesRequestWire, error) { if v == nil { return nil, nil } + servicePrincipalIdWireValue, err := int64ToWire(v.ServicePrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListServicePrincipalFederationPoliciesRequest.ServicePrincipalId", err) + } return &listServicePrincipalFederationPoliciesRequestWire{ AccountId: v.AccountId, - ServicePrincipalId: v.ServicePrincipalId, + ServicePrincipalId: servicePrincipalIdWireValue, PageSize: v.PageSize, PageToken: v.PageToken, }, nil @@ -387,7 +465,7 @@ func servicePrincipalSecretFromWire(w *servicePrincipalSecretWire) (*ServicePrin type updateAccountFederationPolicyRequestWire struct { AccountId *string `json:"account_id,omitempty"` - ServicePrincipalId *int64 `json:"service_principal_id,omitempty"` + ServicePrincipalId *wireInt64 `json:"service_principal_id,omitempty"` PolicyId *string `json:"policy_id,omitempty"` Policy *federationPolicyWire `json:"policy,omitempty"` UpdateMask *string `json:"update_mask,omitempty"` @@ -397,13 +475,17 @@ func updateAccountFederationPolicyRequestToWire(v *UpdateAccountFederationPolicy if v == nil { return nil, nil } + servicePrincipalIdWireValue, err := int64ToWire(v.ServicePrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateAccountFederationPolicyRequest.ServicePrincipalId", err) + } policyWireValue, err := federationPolicyToWire(v.Policy) if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateAccountFederationPolicyRequest.Policy", err) } return &updateAccountFederationPolicyRequestWire{ AccountId: v.AccountId, - ServicePrincipalId: v.ServicePrincipalId, + ServicePrincipalId: servicePrincipalIdWireValue, PolicyId: v.PolicyId, Policy: policyWireValue, UpdateMask: fieldMaskToWire(v.UpdateMask), @@ -412,7 +494,7 @@ func updateAccountFederationPolicyRequestToWire(v *UpdateAccountFederationPolicy type updateServicePrincipalFederationPolicyRequestWire struct { AccountId *string `json:"account_id,omitempty"` - ServicePrincipalId *int64 `json:"service_principal_id,omitempty"` + ServicePrincipalId *wireInt64 `json:"service_principal_id,omitempty"` PolicyId *string `json:"policy_id,omitempty"` Policy *federationPolicyWire `json:"policy,omitempty"` UpdateMask *string `json:"update_mask,omitempty"` @@ -422,13 +504,17 @@ func updateServicePrincipalFederationPolicyRequestToWire(v *UpdateServicePrincip if v == nil { return nil, nil } + servicePrincipalIdWireValue, err := int64ToWire(v.ServicePrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateServicePrincipalFederationPolicyRequest.ServicePrincipalId", err) + } policyWireValue, err := federationPolicyToWire(v.Policy) if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateServicePrincipalFederationPolicyRequest.Policy", err) } return &updateServicePrincipalFederationPolicyRequestWire{ AccountId: v.AccountId, - ServicePrincipalId: v.ServicePrincipalId, + ServicePrincipalId: servicePrincipalIdWireValue, PolicyId: v.PolicyId, Policy: policyWireValue, UpdateMask: fieldMaskToWire(v.UpdateMask), diff --git a/budgetpolicy/CHANGELOG.md b/budgetpolicy/CHANGELOG.md index 6224c04..19f237c 100644 --- a/budgetpolicy/CHANGELOG.md +++ b/budgetpolicy/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/budgetpolicy/go.mod b/budgetpolicy/go.mod index 04440e2..d879e07 100644 --- a/budgetpolicy/go.mod +++ b/budgetpolicy/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/budgetpolicy/internal/version.go b/budgetpolicy/internal/version.go index a151038..8e29cee 100644 --- a/budgetpolicy/internal/version.go +++ b/budgetpolicy/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-budgetpolicy" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/budgetpolicy/v1/client.go b/budgetpolicy/v1/client.go old mode 100755 new mode 100644 index e5acf7c..243a656 --- a/budgetpolicy/v1/client.go +++ b/budgetpolicy/v1/client.go @@ -76,8 +76,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Creates a new policy. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateBudgetPolicy(ctx context.Context, req *CreateBudgetPolicyRequest, opts ...call.Option) (*BudgetPolicy, error) { - wireReq, err := createBudgetPolicyRequestToWire(req) +func (c *internalClient) CreateBudgetPolicy(ctx context.Context, req CreateBudgetPolicyRequest, opts ...call.Option) (*BudgetPolicy, error) { + wireReq, err := createBudgetPolicyRequestToWire(&req) if err != nil { return nil, err } @@ -151,7 +151,7 @@ func (c *internalClient) CreateBudgetPolicy(ctx context.Context, req *CreateBudg // Deletes a policy // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteBudgetPolicy(ctx context.Context, req *DeleteBudgetPolicyRequest, opts ...call.Option) error { +func (c *internalClient) DeleteBudgetPolicy(ctx context.Context, req DeleteBudgetPolicyRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -168,7 +168,11 @@ func (c *internalClient) DeleteBudgetPolicy(ctx context.Context, req *DeleteBudg pb.literal("/api/2.1/accounts/") pb.singleSegment(accountID) pb.literal("/budget-policies/") - pb.singleSegment(*req.PolicyId) + if req.PolicyId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PolicyId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -206,7 +210,7 @@ func (c *internalClient) DeleteBudgetPolicy(ctx context.Context, req *DeleteBudg // Retrieves a policy by it's ID. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetBudgetPolicy(ctx context.Context, req *GetBudgetPolicyRequest, opts ...call.Option) (*BudgetPolicy, error) { +func (c *internalClient) GetBudgetPolicy(ctx context.Context, req GetBudgetPolicyRequest, opts ...call.Option) (*BudgetPolicy, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -223,7 +227,11 @@ func (c *internalClient) GetBudgetPolicy(ctx context.Context, req *GetBudgetPoli pb.literal("/api/2.1/accounts/") pb.singleSegment(accountID) pb.literal("/budget-policies/") - pb.singleSegment(*req.PolicyId) + if req.PolicyId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PolicyId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -271,8 +279,8 @@ func (c *internalClient) GetBudgetPolicy(ctx context.Context, req *GetBudgetPoli // Lists all policies. Policies are returned in the alphabetically ascending // order of their names. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListBudgetPolicies(ctx context.Context, req *ListBudgetPoliciesRequest, opts ...call.Option) (*ListBudgetPoliciesResponse, error) { - wireReq, err := listBudgetPoliciesRequestToWire(req) +func (c *internalClient) ListBudgetPolicies(ctx context.Context, req ListBudgetPoliciesRequest, opts ...call.Option) (*ListBudgetPoliciesResponse, error) { + wireReq, err := listBudgetPoliciesRequestToWire(&req) if err != nil { return nil, err } @@ -353,7 +361,7 @@ func (c *internalClient) ListBudgetPolicies(ctx context.Context, req *ListBudget // // For example: // -// for item, err := range c.ListBudgetPoliciesIter(ctx, &ListBudgetPoliciesRequest{}) { +// for item, err := range c.ListBudgetPoliciesIter(ctx, ListBudgetPoliciesRequest{}) { // if err != nil { // return err // } @@ -365,16 +373,13 @@ func (c *internalClient) ListBudgetPolicies(ctx context.Context, req *ListBudget // // Callers who need custom pagination logic should use // ListBudgetPolicies directly. -func (c *internalClient) ListBudgetPoliciesIter(ctx context.Context, req *ListBudgetPoliciesRequest, opts ...call.Option) iter.Seq2[*BudgetPolicy, error] { +func (c *internalClient) ListBudgetPoliciesIter(ctx context.Context, req ListBudgetPoliciesRequest, opts ...call.Option) iter.Seq2[*BudgetPolicy, error] { return func(yield func(*BudgetPolicy, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListBudgetPoliciesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListBudgetPolicies(ctx, &pageReq, opts...) + resp, err := c.ListBudgetPolicies(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -394,8 +399,8 @@ func (c *internalClient) ListBudgetPoliciesIter(ctx context.Context, req *ListBu // Updates a policy // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdateBudgetPolicy(ctx context.Context, req *UpdateBudgetPolicyRequest, opts ...call.Option) (*BudgetPolicy, error) { - wireReq, err := updateBudgetPolicyRequestToWire(req) +func (c *internalClient) UpdateBudgetPolicy(ctx context.Context, req UpdateBudgetPolicyRequest, opts ...call.Option) (*BudgetPolicy, error) { + wireReq, err := updateBudgetPolicyRequestToWire(&req) if err != nil { return nil, err } @@ -419,7 +424,11 @@ func (c *internalClient) UpdateBudgetPolicy(ctx context.Context, req *UpdateBudg pb.literal("/api/2.1/accounts/") pb.singleSegment(accountID) pb.literal("/budget-policies/") - pb.singleSegment(*req.Policy.PolicyId) + if req.Policy == nil || req.Policy.PolicyId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Policy.PolicyId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "limit_config", wireReq.LimitConfig); err != nil { diff --git a/budgetpolicy/v1/genhelper.go b/budgetpolicy/v1/genhelper.go old mode 100755 new mode 100644 index c1bfc83..358c637 --- a/budgetpolicy/v1/genhelper.go +++ b/budgetpolicy/v1/genhelper.go @@ -192,11 +192,12 @@ func generateRequestID() string { return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:16]) } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -209,13 +210,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/budgetpolicy/v1/wire.go b/budgetpolicy/v1/wire.go old mode 100755 new mode 100644 index ae43faf..956b509 --- a/budgetpolicy/v1/wire.go +++ b/budgetpolicy/v1/wire.go @@ -3,14 +3,60 @@ package budgetpolicy import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type budgetPolicyWire struct { PolicyId *string `json:"policy_id,omitempty"` PolicyName *string `json:"policy_name,omitempty"` CustomTags []customPolicyTagWire `json:"custom_tags,omitempty"` - BindingWorkspaceIds []int64 `json:"binding_workspace_ids,omitempty"` + BindingWorkspaceIds []wireInt64 `json:"binding_workspace_ids,omitempty"` } func budgetPolicyToWire(v *BudgetPolicy) (*budgetPolicyWire, error) { @@ -21,11 +67,15 @@ func budgetPolicyToWire(v *BudgetPolicy) (*budgetPolicyWire, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "BudgetPolicy.CustomTags", err) } + bindingWorkspaceIdsWireValue, err := convertSlice(v.BindingWorkspaceIds, int64ToWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BudgetPolicy.BindingWorkspaceIds", err) + } return &budgetPolicyWire{ PolicyId: v.PolicyId, PolicyName: v.PolicyName, CustomTags: customTagsWireValue, - BindingWorkspaceIds: v.BindingWorkspaceIds, + BindingWorkspaceIds: bindingWorkspaceIdsWireValue, }, nil } @@ -37,11 +87,15 @@ func budgetPolicyFromWire(w *budgetPolicyWire) (*BudgetPolicy, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "BudgetPolicy.CustomTags", err) } + bindingWorkspaceIdsPublicValue, err := convertSlice(w.BindingWorkspaceIds, int64FromWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BudgetPolicy.BindingWorkspaceIds", err) + } return &BudgetPolicy{ PolicyId: w.PolicyId, PolicyName: w.PolicyName, CustomTags: customTagsPublicValue, - BindingWorkspaceIds: w.BindingWorkspaceIds, + BindingWorkspaceIds: bindingWorkspaceIdsPublicValue, }, nil } @@ -92,18 +146,22 @@ func customPolicyTagFromWire(w *customPolicyTagWire) (*CustomPolicyTag, error) { } type filterWire struct { - PolicyName *string `json:"policy_name,omitempty"` - CreatorUserId *int64 `json:"creator_user_id,omitempty"` - CreatorUserName *string `json:"creator_user_name,omitempty"` + PolicyName *string `json:"policy_name,omitempty"` + CreatorUserId *wireInt64 `json:"creator_user_id,omitempty"` + CreatorUserName *string `json:"creator_user_name,omitempty"` } func filterToWire(v *Filter) (*filterWire, error) { if v == nil { return nil, nil } + creatorUserIdWireValue, err := int64ToWire(v.CreatorUserId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Filter.CreatorUserId", err) + } return &filterWire{ PolicyName: v.PolicyName, - CreatorUserId: v.CreatorUserId, + CreatorUserId: creatorUserIdWireValue, CreatorUserName: v.CreatorUserName, }, nil } diff --git a/budgets/CHANGELOG.md b/budgets/CHANGELOG.md index 6224c04..19f237c 100644 --- a/budgets/CHANGELOG.md +++ b/budgets/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/budgets/go.mod b/budgets/go.mod index 495cb52..12f2dba 100644 --- a/budgets/go.mod +++ b/budgets/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/budgets/internal/version.go b/budgets/internal/version.go index 70ff57e..f4ac9f7 100644 --- a/budgets/internal/version.go +++ b/budgets/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-budgets" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/budgets/v1/client.go b/budgets/v1/client.go old mode 100755 new mode 100644 index ed5145c..b0ed4b3 --- a/budgets/v1/client.go +++ b/budgets/v1/client.go @@ -77,8 +77,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Create a new budget configuration for an account. For full details, see // https://docs.databricks.com/en/admin/account-settings/budgets.html. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateBudgetConfiguration(ctx context.Context, req *CreateBudgetConfigurationRequest, opts ...call.Option) (*CreateBudgetConfigurationResponse, error) { - wireReq, err := createBudgetConfigurationRequestToWire(req) +func (c *internalClient) CreateBudgetConfiguration(ctx context.Context, req CreateBudgetConfigurationRequest, opts ...call.Option) (*CreateBudgetConfigurationResponse, error) { + wireReq, err := createBudgetConfigurationRequestToWire(&req) if err != nil { return nil, err } @@ -147,7 +147,7 @@ func (c *internalClient) CreateBudgetConfiguration(ctx context.Context, req *Cre // Deletes a budget configuration for an account. Both account and budget // configuration are specified by ID. This cannot be undone. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteBudgetConfiguration(ctx context.Context, req *DeleteBudgetConfigurationRequest, opts ...call.Option) (*DeleteBudgetConfigurationResponse, error) { +func (c *internalClient) DeleteBudgetConfiguration(ctx context.Context, req DeleteBudgetConfigurationRequest, opts ...call.Option) (*DeleteBudgetConfigurationResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -164,7 +164,11 @@ func (c *internalClient) DeleteBudgetConfiguration(ctx context.Context, req *Del pb.literal("/api/2.1/accounts/") pb.singleSegment(accountID) pb.literal("/budgets/") - pb.singleSegment(*req.BudgetId) + if req.BudgetId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.BudgetId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -206,8 +210,8 @@ func (c *internalClient) DeleteBudgetConfiguration(ctx context.Context, req *Del // Gets a budget configuration for an account. Both account and budget // configuration are specified by ID. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetBudgetConfiguration(ctx context.Context, req *GetBudgetConfigurationRequest, opts ...call.Option) (*GetBudgetConfigurationResponse, error) { - wireReq, err := getBudgetConfigurationRequestToWire(req) +func (c *internalClient) GetBudgetConfiguration(ctx context.Context, req GetBudgetConfigurationRequest, opts ...call.Option) (*GetBudgetConfigurationResponse, error) { + wireReq, err := getBudgetConfigurationRequestToWire(&req) if err != nil { return nil, err } @@ -227,7 +231,11 @@ func (c *internalClient) GetBudgetConfiguration(ctx context.Context, req *GetBud pb.literal("/api/2.1/accounts/") pb.singleSegment(accountID) pb.literal("/budgets/") - pb.singleSegment(*req.BudgetId) + if req.BudgetId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.BudgetId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "include_spend_status", wireReq.IncludeSpendStatus); err != nil { @@ -277,8 +285,8 @@ func (c *internalClient) GetBudgetConfiguration(ctx context.Context, req *GetBud // Gets all budgets associated with this account. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListBudgetConfigurations(ctx context.Context, req *ListBudgetConfigurationsRequest, opts ...call.Option) (*ListBudgetConfigurationsResponse, error) { - wireReq, err := listBudgetConfigurationsRequestToWire(req) +func (c *internalClient) ListBudgetConfigurations(ctx context.Context, req ListBudgetConfigurationsRequest, opts ...call.Option) (*ListBudgetConfigurationsResponse, error) { + wireReq, err := listBudgetConfigurationsRequestToWire(&req) if err != nil { return nil, err } @@ -356,7 +364,7 @@ func (c *internalClient) ListBudgetConfigurations(ctx context.Context, req *List // // For example: // -// for item, err := range c.ListBudgetConfigurationsIter(ctx, &ListBudgetConfigurationsRequest{}) { +// for item, err := range c.ListBudgetConfigurationsIter(ctx, ListBudgetConfigurationsRequest{}) { // if err != nil { // return err // } @@ -368,16 +376,13 @@ func (c *internalClient) ListBudgetConfigurations(ctx context.Context, req *List // // Callers who need custom pagination logic should use // ListBudgetConfigurations directly. -func (c *internalClient) ListBudgetConfigurationsIter(ctx context.Context, req *ListBudgetConfigurationsRequest, opts ...call.Option) iter.Seq2[*BudgetConfiguration, error] { +func (c *internalClient) ListBudgetConfigurationsIter(ctx context.Context, req ListBudgetConfigurationsRequest, opts ...call.Option) iter.Seq2[*BudgetConfiguration, error] { return func(yield func(*BudgetConfiguration, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListBudgetConfigurationsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListBudgetConfigurations(ctx, &pageReq, opts...) + resp, err := c.ListBudgetConfigurations(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -398,8 +403,8 @@ func (c *internalClient) ListBudgetConfigurationsIter(ctx context.Context, req * // Updates a budget configuration for an account. Both account and budget // configuration are specified by ID. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdateBudgetConfiguration(ctx context.Context, req *UpdateBudgetConfigurationRequest, opts ...call.Option) (*UpdateBudgetConfigurationResponse, error) { - wireReq, err := updateBudgetConfigurationRequestToWire(req) +func (c *internalClient) UpdateBudgetConfiguration(ctx context.Context, req UpdateBudgetConfigurationRequest, opts ...call.Option) (*UpdateBudgetConfigurationResponse, error) { + wireReq, err := updateBudgetConfigurationRequestToWire(&req) if err != nil { return nil, err } @@ -420,7 +425,11 @@ func (c *internalClient) UpdateBudgetConfiguration(ctx context.Context, req *Upd pb.literal("/api/2.1/accounts/") pb.singleSegment(accountID) pb.literal("/budgets/") - pb.singleSegment(*req.BudgetId) + if req.BudgetId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.BudgetId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/budgets/v1/genhelper.go b/budgets/v1/genhelper.go old mode 100755 new mode 100644 index 5128aa3..5ba57bc --- a/budgets/v1/genhelper.go +++ b/budgets/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/budgets/v1/wire.go b/budgets/v1/wire.go old mode 100755 new mode 100644 index 82b7f17..8a6b56f --- a/budgets/v1/wire.go +++ b/budgets/v1/wire.go @@ -3,9 +3,55 @@ package budgets import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type actionConfigurationWire struct { ActionConfigurationId *string `json:"action_configuration_id,omitempty"` ActionType ActionConfigurationType `json:"action_type,omitempty"` @@ -96,8 +142,8 @@ func alertConfigurationFromWire(w *alertConfigurationWire) (*AlertConfiguration, type budgetConfigurationWire struct { BudgetConfigurationId *string `json:"budget_configuration_id,omitempty"` AccountId *string `json:"account_id,omitempty"` - CreateTime *int64 `json:"create_time,omitempty"` - UpdateTime *int64 `json:"update_time,omitempty"` + CreateTime *wireInt64 `json:"create_time,omitempty"` + UpdateTime *wireInt64 `json:"update_time,omitempty"` AlertConfigurations []alertConfigurationWire `json:"alert_configurations,omitempty"` Filter *budgetConfigurationFilterWire `json:"filter,omitempty"` DisplayName *string `json:"display_name,omitempty"` @@ -108,6 +154,14 @@ func budgetConfigurationFromWire(w *budgetConfigurationWire) (*BudgetConfigurati if w == nil { return nil, nil } + createTimePublicValue, err := int64FromWire(w.CreateTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BudgetConfiguration.CreateTime", err) + } + updateTimePublicValue, err := int64FromWire(w.UpdateTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BudgetConfiguration.UpdateTime", err) + } alertConfigurationsPublicValue, err := convertSlice(w.AlertConfigurations, alertConfigurationFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "BudgetConfiguration.AlertConfigurations", err) @@ -119,8 +173,8 @@ func budgetConfigurationFromWire(w *budgetConfigurationWire) (*BudgetConfigurati return &BudgetConfiguration{ BudgetConfigurationId: w.BudgetConfigurationId, AccountId: w.AccountId, - CreateTime: w.CreateTime, - UpdateTime: w.UpdateTime, + CreateTime: createTimePublicValue, + UpdateTime: updateTimePublicValue, AlertConfigurations: alertConfigurationsPublicValue, Filter: filterPublicValue, DisplayName: w.DisplayName, @@ -229,16 +283,20 @@ func budgetConfigurationFilter_TagClauseFromWire(w *budgetConfigurationFilter_Ta type budgetConfigurationFilter_WorkspaceIdClauseWire struct { Operator BudgetConfigurationFilter_Operator `json:"operator,omitempty"` - Values []int64 `json:"values,omitempty"` + Values []wireInt64 `json:"values,omitempty"` } func budgetConfigurationFilter_WorkspaceIdClauseToWire(v *BudgetConfigurationFilter_WorkspaceIdClause) (*budgetConfigurationFilter_WorkspaceIdClauseWire, error) { if v == nil { return nil, nil } + valuesWireValue, err := convertSlice(v.Values, int64ToWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BudgetConfigurationFilter_WorkspaceIdClause.Values", err) + } return &budgetConfigurationFilter_WorkspaceIdClauseWire{ Operator: v.Operator, - Values: v.Values, + Values: valuesWireValue, }, nil } @@ -246,17 +304,21 @@ func budgetConfigurationFilter_WorkspaceIdClauseFromWire(w *budgetConfigurationF if w == nil { return nil, nil } + valuesPublicValue, err := convertSlice(w.Values, int64FromWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BudgetConfigurationFilter_WorkspaceIdClause.Values", err) + } return &BudgetConfigurationFilter_WorkspaceIdClause{ Operator: w.Operator, - Values: w.Values, + Values: valuesPublicValue, }, nil } type createBudgetConfigurationBudgetWire struct { BudgetConfigurationId *string `json:"budget_configuration_id,omitempty"` AccountId *string `json:"account_id,omitempty"` - CreateTime *int64 `json:"create_time,omitempty"` - UpdateTime *int64 `json:"update_time,omitempty"` + CreateTime *wireInt64 `json:"create_time,omitempty"` + UpdateTime *wireInt64 `json:"update_time,omitempty"` AlertConfigurations []alertConfigurationWire `json:"alert_configurations,omitempty"` Filter *budgetConfigurationFilterWire `json:"filter,omitempty"` DisplayName *string `json:"display_name,omitempty"` @@ -267,6 +329,14 @@ func createBudgetConfigurationBudgetToWire(v *CreateBudgetConfigurationBudget) ( if v == nil { return nil, nil } + createTimeWireValue, err := int64ToWire(v.CreateTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateBudgetConfigurationBudget.CreateTime", err) + } + updateTimeWireValue, err := int64ToWire(v.UpdateTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateBudgetConfigurationBudget.UpdateTime", err) + } alertConfigurationsWireValue, err := convertSlice(v.AlertConfigurations, alertConfigurationToWire) if err != nil { return nil, fmt.Errorf("%s: %w", "CreateBudgetConfigurationBudget.AlertConfigurations", err) @@ -278,8 +348,8 @@ func createBudgetConfigurationBudgetToWire(v *CreateBudgetConfigurationBudget) ( return &createBudgetConfigurationBudgetWire{ BudgetConfigurationId: v.BudgetConfigurationId, AccountId: v.AccountId, - CreateTime: v.CreateTime, - UpdateTime: v.UpdateTime, + CreateTime: createTimeWireValue, + UpdateTime: updateTimeWireValue, AlertConfigurations: alertConfigurationsWireValue, Filter: filterWireValue, DisplayName: v.DisplayName, @@ -394,16 +464,20 @@ func listBudgetConfigurationsResponseFromWire(w *listBudgetConfigurationsRespons } type principalOverrideWire struct { - PrincipalId *int64 `json:"principal_id,omitempty"` - OverrideThreshold *string `json:"override_threshold,omitempty"` + PrincipalId *wireInt64 `json:"principal_id,omitempty"` + OverrideThreshold *string `json:"override_threshold,omitempty"` } func principalOverrideToWire(v *PrincipalOverride) (*principalOverrideWire, error) { if v == nil { return nil, nil } + principalIdWireValue, err := int64ToWire(v.PrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PrincipalOverride.PrincipalId", err) + } return &principalOverrideWire{ - PrincipalId: v.PrincipalId, + PrincipalId: principalIdWireValue, OverrideThreshold: v.OverrideThreshold, }, nil } @@ -412,8 +486,12 @@ func principalOverrideFromWire(w *principalOverrideWire) (*PrincipalOverride, er if w == nil { return nil, nil } + principalIdPublicValue, err := int64FromWire(w.PrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PrincipalOverride.PrincipalId", err) + } return &PrincipalOverride{ - PrincipalId: w.PrincipalId, + PrincipalId: principalIdPublicValue, OverrideThreshold: w.OverrideThreshold, }, nil } @@ -421,8 +499,8 @@ func principalOverrideFromWire(w *principalOverrideWire) (*PrincipalOverride, er type updateBudgetConfigurationBudgetWire struct { BudgetConfigurationId *string `json:"budget_configuration_id,omitempty"` AccountId *string `json:"account_id,omitempty"` - CreateTime *int64 `json:"create_time,omitempty"` - UpdateTime *int64 `json:"update_time,omitempty"` + CreateTime *wireInt64 `json:"create_time,omitempty"` + UpdateTime *wireInt64 `json:"update_time,omitempty"` AlertConfigurations []alertConfigurationWire `json:"alert_configurations,omitempty"` Filter *budgetConfigurationFilterWire `json:"filter,omitempty"` DisplayName *string `json:"display_name,omitempty"` @@ -433,6 +511,14 @@ func updateBudgetConfigurationBudgetToWire(v *UpdateBudgetConfigurationBudget) ( if v == nil { return nil, nil } + createTimeWireValue, err := int64ToWire(v.CreateTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateBudgetConfigurationBudget.CreateTime", err) + } + updateTimeWireValue, err := int64ToWire(v.UpdateTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateBudgetConfigurationBudget.UpdateTime", err) + } alertConfigurationsWireValue, err := convertSlice(v.AlertConfigurations, alertConfigurationToWire) if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateBudgetConfigurationBudget.AlertConfigurations", err) @@ -444,8 +530,8 @@ func updateBudgetConfigurationBudgetToWire(v *UpdateBudgetConfigurationBudget) ( return &updateBudgetConfigurationBudgetWire{ BudgetConfigurationId: v.BudgetConfigurationId, AccountId: v.AccountId, - CreateTime: v.CreateTime, - UpdateTime: v.UpdateTime, + CreateTime: createTimeWireValue, + UpdateTime: updateTimeWireValue, AlertConfigurations: alertConfigurationsWireValue, Filter: filterWireValue, DisplayName: v.DisplayName, diff --git a/cleanrooms/CHANGELOG.md b/cleanrooms/CHANGELOG.md index 6224c04..19f237c 100644 --- a/cleanrooms/CHANGELOG.md +++ b/cleanrooms/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/cleanrooms/go.mod b/cleanrooms/go.mod index 35a5d6e..5a7d599 100644 --- a/cleanrooms/go.mod +++ b/cleanrooms/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/cleanrooms/internal/version.go b/cleanrooms/internal/version.go index bc5c3e7..07911a9 100644 --- a/cleanrooms/internal/version.go +++ b/cleanrooms/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-cleanrooms" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/cleanrooms/v1/client.go b/cleanrooms/v1/client.go old mode 100755 new mode 100644 index 1fbb613..fdfbd61 --- a/cleanrooms/v1/client.go +++ b/cleanrooms/v1/client.go @@ -87,8 +87,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // privilege on the metastore. // // [cleanrooms/get]: https://docs.databricks.com/api/workspace/cleanrooms/get -func (c *internalClient) createCleanRoomBase(ctx context.Context, req *CreateCleanRoomRequest, opts ...call.Option) (*CleanRoom, error) { - wireReq, err := createCleanRoomRequestToWire(req) +func (c *internalClient) createCleanRoomBase(ctx context.Context, req CreateCleanRoomRequest, opts ...call.Option) (*CleanRoom, error) { + wireReq, err := createCleanRoomRequestToWire(&req) if err != nil { return nil, err } @@ -163,7 +163,7 @@ func (c *internalClient) createCleanRoomBase(ctx context.Context, req *CreateCle // privilege on the metastore. // // [cleanrooms/get]: https://docs.databricks.com/api/workspace/cleanrooms/get -func (c *internalClient) CreateCleanRoom(ctx context.Context, req *CreateCleanRoomRequest, opts ...call.Option) (*CreateCleanRoomWaiter, error) { +func (c *internalClient) CreateCleanRoom(ctx context.Context, req CreateCleanRoomRequest, opts ...call.Option) (*CreateCleanRoomWaiter, error) { resp, err := c.createCleanRoomBase(ctx, req, opts...) if err != nil { return nil, err @@ -179,13 +179,18 @@ func (c *internalClient) CreateCleanRoom(ctx context.Context, req *CreateCleanRo // CreateCleanRoomWaiter tracks the state of the operation started by CreateCleanRoom. type CreateCleanRoomWaiter struct { - poll func(context.Context, *GetCleanRoomRequest, ...call.Option) (*CleanRoom, error) + poll func(context.Context, GetCleanRoomRequest, ...call.Option) (*CleanRoom, error) name string } +// GetName returns the Name value used to identify the operation. +func (w *CreateCleanRoomWaiter) GetName() string { + return w.name +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *CreateCleanRoomWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetCleanRoomRequest{ + pollResp, err := w.poll(ctx, GetCleanRoomRequest{ Name: &w.name, }, opts...) if err != nil { @@ -210,7 +215,7 @@ func (w *CreateCleanRoomWaiter) Done(ctx context.Context, opts ...call.Option) ( func (w *CreateCleanRoomWaiter) Wait(ctx context.Context, opts ...lro.Option) (*CleanRoom, error) { var result *CleanRoom poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetCleanRoomRequest{ + pollResp, err := w.poll(ctx, GetCleanRoomRequest{ Name: &w.name, }) if err != nil { @@ -242,8 +247,8 @@ func (w *CreateCleanRoomWaiter) Wait(ctx context.Context, opts ...lro.Option) (* // room owner must also have enough privilege on the asset to consume it. The // privilege must be maintained indefinitely for the clean room to be able to // access the asset. Typically, you should use a group as the clean room owner. -func (c *internalClient) CreateCleanRoomAsset(ctx context.Context, req *CreateCleanRoomAssetRequest, opts ...call.Option) (*CleanRoomAsset, error) { - wireReq, err := createCleanRoomAssetRequestToWire(req) +func (c *internalClient) CreateCleanRoomAsset(ctx context.Context, req CreateCleanRoomAssetRequest, opts ...call.Option) (*CleanRoomAsset, error) { + wireReq, err := createCleanRoomAssetRequestToWire(&req) if err != nil { return nil, err } @@ -264,7 +269,11 @@ func (c *internalClient) CreateCleanRoomAsset(ctx context.Context, req *CreateCl } pb := pathBuilder{} pb.literal("/api/2.0/clean-rooms/") - pb.singleSegment(*req.Asset.CleanRoomName) + if req.Asset == nil || req.Asset.CleanRoomName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Asset.CleanRoomName) + } pb.literal("/assets") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -312,8 +321,8 @@ func (c *internalClient) CreateCleanRoomAsset(ctx context.Context, req *CreateCl } // Submit an asset review -func (c *internalClient) CreateCleanRoomAssetReview(ctx context.Context, req *CreateCleanRoomAssetReviewRequest, opts ...call.Option) (*CreateCleanRoomAssetReviewResponse, error) { - wireReq, err := createCleanRoomAssetReviewRequestToWire(req) +func (c *internalClient) CreateCleanRoomAssetReview(ctx context.Context, req CreateCleanRoomAssetReviewRequest, opts ...call.Option) (*CreateCleanRoomAssetReviewResponse, error) { + wireReq, err := createCleanRoomAssetReviewRequestToWire(&req) if err != nil { return nil, err } @@ -332,16 +341,21 @@ func (c *internalClient) CreateCleanRoomAssetReview(ctx context.Context, req *Cr if err != nil { return nil, err } - if req.AssetType == "" { - return nil, fmt.Errorf("path parameter %q is required", "asset_type") - } pb := pathBuilder{} pb.literal("/api/2.0/clean-rooms/") - pb.singleSegment(*req.CleanRoomName) + if req.CleanRoomName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CleanRoomName) + } pb.literal("/assets/") pb.singleSegment(req.AssetType) pb.literal("/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/reviews") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -389,8 +403,8 @@ func (c *internalClient) CreateCleanRoomAssetReview(ctx context.Context, req *Cr } // Create an auto-approval rule -func (c *internalClient) CreateCleanRoomAutoApprovalRule(ctx context.Context, req *CreateCleanRoomAutoApprovalRuleRequest, opts ...call.Option) (*CleanRoomAutoApprovalRule, error) { - wireReq, err := createCleanRoomAutoApprovalRuleRequestToWire(req) +func (c *internalClient) CreateCleanRoomAutoApprovalRule(ctx context.Context, req CreateCleanRoomAutoApprovalRuleRequest, opts ...call.Option) (*CleanRoomAutoApprovalRule, error) { + wireReq, err := createCleanRoomAutoApprovalRuleRequestToWire(&req) if err != nil { return nil, err } @@ -411,7 +425,11 @@ func (c *internalClient) CreateCleanRoomAutoApprovalRule(ctx context.Context, re } pb := pathBuilder{} pb.literal("/api/2.0/clean-rooms/") - pb.singleSegment(*req.AutoApprovalRule.CleanRoomName) + if req.AutoApprovalRule == nil || req.AutoApprovalRule.CleanRoomName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.AutoApprovalRule.CleanRoomName) + } pb.literal("/auto-approval-rules") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -459,8 +477,8 @@ func (c *internalClient) CreateCleanRoomAutoApprovalRule(ctx context.Context, re } // Create the output catalog of the clean room. -func (c *internalClient) CreateCleanRoomOutputCatalog(ctx context.Context, req *CreateCleanRoomOutputCatalogRequest, opts ...call.Option) (*CreateCleanRoomOutputCatalogResponse, error) { - wireReq, err := createCleanRoomOutputCatalogRequestToWire(req) +func (c *internalClient) CreateCleanRoomOutputCatalog(ctx context.Context, req CreateCleanRoomOutputCatalogRequest, opts ...call.Option) (*CreateCleanRoomOutputCatalogResponse, error) { + wireReq, err := createCleanRoomOutputCatalogRequestToWire(&req) if err != nil { return nil, err } @@ -481,7 +499,11 @@ func (c *internalClient) CreateCleanRoomOutputCatalog(ctx context.Context, req * } pb := pathBuilder{} pb.literal("/api/2.0/clean-rooms/") - pb.singleSegment(*req.CleanRoomName) + if req.CleanRoomName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CleanRoomName) + } pb.literal("/output-catalogs") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -532,7 +554,7 @@ func (c *internalClient) CreateCleanRoomOutputCatalog(ctx context.Context, req * // metastore. If the other collaborators have not deleted the clean room, they // will still have the clean room in their metastore, but it will be in a // DELETED state and no operations other than deletion can be performed on it. -func (c *internalClient) DeleteCleanRoom(ctx context.Context, req *DeleteCleanRoomRequest, opts ...call.Option) error { +func (c *internalClient) DeleteCleanRoom(ctx context.Context, req DeleteCleanRoomRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -546,7 +568,11 @@ func (c *internalClient) DeleteCleanRoom(ctx context.Context, req *DeleteCleanRo } pb := pathBuilder{} pb.literal("/api/2.0/clean-rooms/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -583,7 +609,7 @@ func (c *internalClient) DeleteCleanRoom(ctx context.Context, req *DeleteCleanRo } // Delete a clean room asset - unshare/remove the asset from the clean room -func (c *internalClient) DeleteCleanRoomAsset(ctx context.Context, req *DeleteCleanRoomAssetRequest, opts ...call.Option) (*DeleteCleanRoomAssetResponse, error) { +func (c *internalClient) DeleteCleanRoomAsset(ctx context.Context, req DeleteCleanRoomAssetRequest, opts ...call.Option) (*DeleteCleanRoomAssetResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -595,16 +621,21 @@ func (c *internalClient) DeleteCleanRoomAsset(ctx context.Context, req *DeleteCl if err != nil { return nil, err } - if req.AssetType == "" { - return nil, fmt.Errorf("path parameter %q is required", "asset_type") - } pb := pathBuilder{} pb.literal("/api/2.0/clean-rooms/") - pb.singleSegment(*req.CleanRoomName) + if req.CleanRoomName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CleanRoomName) + } pb.literal("/assets/") pb.singleSegment(req.AssetType) pb.literal("/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -644,7 +675,7 @@ func (c *internalClient) DeleteCleanRoomAsset(ctx context.Context, req *DeleteCl } // Delete a auto-approval rule by rule ID -func (c *internalClient) DeleteCleanRoomAutoApprovalRule(ctx context.Context, req *DeleteCleanRoomAutoApprovalRuleRequest, opts ...call.Option) error { +func (c *internalClient) DeleteCleanRoomAutoApprovalRule(ctx context.Context, req DeleteCleanRoomAutoApprovalRuleRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -658,9 +689,17 @@ func (c *internalClient) DeleteCleanRoomAutoApprovalRule(ctx context.Context, re } pb := pathBuilder{} pb.literal("/api/2.0/clean-rooms/") - pb.singleSegment(*req.CleanRoomName) + if req.CleanRoomName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CleanRoomName) + } pb.literal("/auto-approval-rules/") - pb.singleSegment(*req.RuleId) + if req.RuleId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.RuleId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -697,7 +736,7 @@ func (c *internalClient) DeleteCleanRoomAutoApprovalRule(ctx context.Context, re } // Get the details of a clean room given its name. -func (c *internalClient) GetCleanRoom(ctx context.Context, req *GetCleanRoomRequest, opts ...call.Option) (*CleanRoom, error) { +func (c *internalClient) GetCleanRoom(ctx context.Context, req GetCleanRoomRequest, opts ...call.Option) (*CleanRoom, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -711,7 +750,11 @@ func (c *internalClient) GetCleanRoom(ctx context.Context, req *GetCleanRoomRequ } pb := pathBuilder{} pb.literal("/api/2.0/clean-rooms/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -757,7 +800,7 @@ func (c *internalClient) GetCleanRoom(ctx context.Context, req *GetCleanRoomRequ } // Get the details of a clean room asset by its type and full name. -func (c *internalClient) GetCleanRoomAsset(ctx context.Context, req *GetCleanRoomAssetRequest, opts ...call.Option) (*CleanRoomAsset, error) { +func (c *internalClient) GetCleanRoomAsset(ctx context.Context, req GetCleanRoomAssetRequest, opts ...call.Option) (*CleanRoomAsset, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -769,16 +812,21 @@ func (c *internalClient) GetCleanRoomAsset(ctx context.Context, req *GetCleanRoo if err != nil { return nil, err } - if req.AssetType == "" { - return nil, fmt.Errorf("path parameter %q is required", "asset_type") - } pb := pathBuilder{} pb.literal("/api/2.0/clean-rooms/") - pb.singleSegment(*req.CleanRoomName) + if req.CleanRoomName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CleanRoomName) + } pb.literal("/assets/") pb.singleSegment(req.AssetType) pb.literal("/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -824,7 +872,7 @@ func (c *internalClient) GetCleanRoomAsset(ctx context.Context, req *GetCleanRoo } // Get a specific revision of an asset -func (c *internalClient) GetCleanRoomAssetRevision(ctx context.Context, req *GetCleanRoomAssetRevisionRequest, opts ...call.Option) (*CleanRoomAsset, error) { +func (c *internalClient) GetCleanRoomAssetRevision(ctx context.Context, req GetCleanRoomAssetRevisionRequest, opts ...call.Option) (*CleanRoomAsset, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -836,18 +884,27 @@ func (c *internalClient) GetCleanRoomAssetRevision(ctx context.Context, req *Get if err != nil { return nil, err } - if req.AssetType == "" { - return nil, fmt.Errorf("path parameter %q is required", "asset_type") - } pb := pathBuilder{} pb.literal("/api/2.0/clean-rooms/") - pb.singleSegment(*req.CleanRoomName) + if req.CleanRoomName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CleanRoomName) + } pb.literal("/assets/") pb.singleSegment(req.AssetType) pb.literal("/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/revisions/") - pb.singleSegment(*req.Etag) + if req.Etag == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Etag) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -893,7 +950,7 @@ func (c *internalClient) GetCleanRoomAssetRevision(ctx context.Context, req *Get } // Get a auto-approval rule by rule ID -func (c *internalClient) GetCleanRoomAutoApprovalRule(ctx context.Context, req *GetCleanRoomAutoApprovalRuleRequest, opts ...call.Option) (*CleanRoomAutoApprovalRule, error) { +func (c *internalClient) GetCleanRoomAutoApprovalRule(ctx context.Context, req GetCleanRoomAutoApprovalRuleRequest, opts ...call.Option) (*CleanRoomAutoApprovalRule, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -907,9 +964,17 @@ func (c *internalClient) GetCleanRoomAutoApprovalRule(ctx context.Context, req * } pb := pathBuilder{} pb.literal("/api/2.0/clean-rooms/") - pb.singleSegment(*req.CleanRoomName) + if req.CleanRoomName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CleanRoomName) + } pb.literal("/auto-approval-rules/") - pb.singleSegment(*req.RuleId) + if req.RuleId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.RuleId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -955,8 +1020,8 @@ func (c *internalClient) GetCleanRoomAutoApprovalRule(ctx context.Context, req * } // List revisions for an asset -func (c *internalClient) ListCleanRoomAssetRevisions(ctx context.Context, req *ListCleanRoomAssetRevisionsRequest, opts ...call.Option) (*ListCleanRoomAssetRevisionsResponse, error) { - wireReq, err := listCleanRoomAssetRevisionsRequestToWire(req) +func (c *internalClient) ListCleanRoomAssetRevisions(ctx context.Context, req ListCleanRoomAssetRevisionsRequest, opts ...call.Option) (*ListCleanRoomAssetRevisionsResponse, error) { + wireReq, err := listCleanRoomAssetRevisionsRequestToWire(&req) if err != nil { return nil, err } @@ -971,16 +1036,21 @@ func (c *internalClient) ListCleanRoomAssetRevisions(ctx context.Context, req *L if err != nil { return nil, err } - if req.AssetType == "" { - return nil, fmt.Errorf("path parameter %q is required", "asset_type") - } pb := pathBuilder{} pb.literal("/api/2.0/clean-rooms/") - pb.singleSegment(*req.CleanRoomName) + if req.CleanRoomName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CleanRoomName) + } pb.literal("/assets/") pb.singleSegment(req.AssetType) pb.literal("/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/revisions") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1037,7 +1107,7 @@ func (c *internalClient) ListCleanRoomAssetRevisions(ctx context.Context, req *L // // For example: // -// for item, err := range c.ListCleanRoomAssetRevisionsIter(ctx, &ListCleanRoomAssetRevisionsRequest{}) { +// for item, err := range c.ListCleanRoomAssetRevisionsIter(ctx, ListCleanRoomAssetRevisionsRequest{}) { // if err != nil { // return err // } @@ -1049,16 +1119,13 @@ func (c *internalClient) ListCleanRoomAssetRevisions(ctx context.Context, req *L // // Callers who need custom pagination logic should use // ListCleanRoomAssetRevisions directly. -func (c *internalClient) ListCleanRoomAssetRevisionsIter(ctx context.Context, req *ListCleanRoomAssetRevisionsRequest, opts ...call.Option) iter.Seq2[*CleanRoomAsset, error] { +func (c *internalClient) ListCleanRoomAssetRevisionsIter(ctx context.Context, req ListCleanRoomAssetRevisionsRequest, opts ...call.Option) iter.Seq2[*CleanRoomAsset, error] { return func(yield func(*CleanRoomAsset, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListCleanRoomAssetRevisionsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListCleanRoomAssetRevisions(ctx, &pageReq, opts...) + resp, err := c.ListCleanRoomAssetRevisions(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1077,8 +1144,8 @@ func (c *internalClient) ListCleanRoomAssetRevisionsIter(ctx context.Context, re } // List assets. -func (c *internalClient) ListCleanRoomAssets(ctx context.Context, req *ListCleanRoomAssetsRequest, opts ...call.Option) (*ListCleanRoomAssetsResponse, error) { - wireReq, err := listCleanRoomAssetsRequestToWire(req) +func (c *internalClient) ListCleanRoomAssets(ctx context.Context, req ListCleanRoomAssetsRequest, opts ...call.Option) (*ListCleanRoomAssetsResponse, error) { + wireReq, err := listCleanRoomAssetsRequestToWire(&req) if err != nil { return nil, err } @@ -1095,7 +1162,11 @@ func (c *internalClient) ListCleanRoomAssets(ctx context.Context, req *ListClean } pb := pathBuilder{} pb.literal("/api/2.0/clean-rooms/") - pb.singleSegment(*req.CleanRoomName) + if req.CleanRoomName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CleanRoomName) + } pb.literal("/assets") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1149,7 +1220,7 @@ func (c *internalClient) ListCleanRoomAssets(ctx context.Context, req *ListClean // // For example: // -// for item, err := range c.ListCleanRoomAssetsIter(ctx, &ListCleanRoomAssetsRequest{}) { +// for item, err := range c.ListCleanRoomAssetsIter(ctx, ListCleanRoomAssetsRequest{}) { // if err != nil { // return err // } @@ -1161,16 +1232,13 @@ func (c *internalClient) ListCleanRoomAssets(ctx context.Context, req *ListClean // // Callers who need custom pagination logic should use // ListCleanRoomAssets directly. -func (c *internalClient) ListCleanRoomAssetsIter(ctx context.Context, req *ListCleanRoomAssetsRequest, opts ...call.Option) iter.Seq2[*CleanRoomAsset, error] { +func (c *internalClient) ListCleanRoomAssetsIter(ctx context.Context, req ListCleanRoomAssetsRequest, opts ...call.Option) iter.Seq2[*CleanRoomAsset, error] { return func(yield func(*CleanRoomAsset, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListCleanRoomAssetsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListCleanRoomAssets(ctx, &pageReq, opts...) + resp, err := c.ListCleanRoomAssets(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1189,8 +1257,8 @@ func (c *internalClient) ListCleanRoomAssetsIter(ctx context.Context, req *ListC } // List all auto-approval rules for the caller -func (c *internalClient) ListCleanRoomAutoApprovalRules(ctx context.Context, req *ListCleanRoomAutoApprovalRulesRequest, opts ...call.Option) (*ListCleanRoomAutoApprovalRulesResponse, error) { - wireReq, err := listCleanRoomAutoApprovalRulesRequestToWire(req) +func (c *internalClient) ListCleanRoomAutoApprovalRules(ctx context.Context, req ListCleanRoomAutoApprovalRulesRequest, opts ...call.Option) (*ListCleanRoomAutoApprovalRulesResponse, error) { + wireReq, err := listCleanRoomAutoApprovalRulesRequestToWire(&req) if err != nil { return nil, err } @@ -1207,7 +1275,11 @@ func (c *internalClient) ListCleanRoomAutoApprovalRules(ctx context.Context, req } pb := pathBuilder{} pb.literal("/api/2.0/clean-rooms/") - pb.singleSegment(*req.CleanRoomName) + if req.CleanRoomName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CleanRoomName) + } pb.literal("/auto-approval-rules") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1264,7 +1336,7 @@ func (c *internalClient) ListCleanRoomAutoApprovalRules(ctx context.Context, req // // For example: // -// for item, err := range c.ListCleanRoomAutoApprovalRulesIter(ctx, &ListCleanRoomAutoApprovalRulesRequest{}) { +// for item, err := range c.ListCleanRoomAutoApprovalRulesIter(ctx, ListCleanRoomAutoApprovalRulesRequest{}) { // if err != nil { // return err // } @@ -1276,16 +1348,13 @@ func (c *internalClient) ListCleanRoomAutoApprovalRules(ctx context.Context, req // // Callers who need custom pagination logic should use // ListCleanRoomAutoApprovalRules directly. -func (c *internalClient) ListCleanRoomAutoApprovalRulesIter(ctx context.Context, req *ListCleanRoomAutoApprovalRulesRequest, opts ...call.Option) iter.Seq2[*CleanRoomAutoApprovalRule, error] { +func (c *internalClient) ListCleanRoomAutoApprovalRulesIter(ctx context.Context, req ListCleanRoomAutoApprovalRulesRequest, opts ...call.Option) iter.Seq2[*CleanRoomAutoApprovalRule, error] { return func(yield func(*CleanRoomAutoApprovalRule, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListCleanRoomAutoApprovalRulesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListCleanRoomAutoApprovalRules(ctx, &pageReq, opts...) + resp, err := c.ListCleanRoomAutoApprovalRules(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1304,8 +1373,8 @@ func (c *internalClient) ListCleanRoomAutoApprovalRulesIter(ctx context.Context, } // List all the historical notebook task runs in a clean room. -func (c *internalClient) ListCleanRoomNotebookTaskRuns(ctx context.Context, req *ListCleanRoomNotebookTaskRunsRequest, opts ...call.Option) (*ListCleanRoomNotebookTaskRunsResponse, error) { - wireReq, err := listCleanRoomNotebookTaskRunsRequestToWire(req) +func (c *internalClient) ListCleanRoomNotebookTaskRuns(ctx context.Context, req ListCleanRoomNotebookTaskRunsRequest, opts ...call.Option) (*ListCleanRoomNotebookTaskRunsResponse, error) { + wireReq, err := listCleanRoomNotebookTaskRunsRequestToWire(&req) if err != nil { return nil, err } @@ -1322,7 +1391,11 @@ func (c *internalClient) ListCleanRoomNotebookTaskRuns(ctx context.Context, req } pb := pathBuilder{} pb.literal("/api/2.0/clean-rooms/") - pb.singleSegment(*req.CleanRoomName) + if req.CleanRoomName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CleanRoomName) + } pb.literal("/runs") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1382,7 +1455,7 @@ func (c *internalClient) ListCleanRoomNotebookTaskRuns(ctx context.Context, req // // For example: // -// for item, err := range c.ListCleanRoomNotebookTaskRunsIter(ctx, &ListCleanRoomNotebookTaskRunsRequest{}) { +// for item, err := range c.ListCleanRoomNotebookTaskRunsIter(ctx, ListCleanRoomNotebookTaskRunsRequest{}) { // if err != nil { // return err // } @@ -1394,16 +1467,13 @@ func (c *internalClient) ListCleanRoomNotebookTaskRuns(ctx context.Context, req // // Callers who need custom pagination logic should use // ListCleanRoomNotebookTaskRuns directly. -func (c *internalClient) ListCleanRoomNotebookTaskRunsIter(ctx context.Context, req *ListCleanRoomNotebookTaskRunsRequest, opts ...call.Option) iter.Seq2[*CleanRoomNotebookTaskRun, error] { +func (c *internalClient) ListCleanRoomNotebookTaskRunsIter(ctx context.Context, req ListCleanRoomNotebookTaskRunsRequest, opts ...call.Option) iter.Seq2[*CleanRoomNotebookTaskRun, error] { return func(yield func(*CleanRoomNotebookTaskRun, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListCleanRoomNotebookTaskRunsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListCleanRoomNotebookTaskRuns(ctx, &pageReq, opts...) + resp, err := c.ListCleanRoomNotebookTaskRuns(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1422,8 +1492,8 @@ func (c *internalClient) ListCleanRoomNotebookTaskRunsIter(ctx context.Context, } // List all the historical task runs in a clean room. -func (c *internalClient) ListCleanRoomTaskRunsHandler(ctx context.Context, req *ListCleanRoomTaskRunsRequest, opts ...call.Option) (*ListCleanRoomTaskRunsResponse, error) { - wireReq, err := listCleanRoomTaskRunsRequestToWire(req) +func (c *internalClient) ListCleanRoomTaskRunsHandler(ctx context.Context, req ListCleanRoomTaskRunsRequest, opts ...call.Option) (*ListCleanRoomTaskRunsResponse, error) { + wireReq, err := listCleanRoomTaskRunsRequestToWire(&req) if err != nil { return nil, err } @@ -1440,7 +1510,11 @@ func (c *internalClient) ListCleanRoomTaskRunsHandler(ctx context.Context, req * } pb := pathBuilder{} pb.literal("/api/2.0/clean-rooms/") - pb.singleSegment(*req.CleanRoomName) + if req.CleanRoomName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CleanRoomName) + } pb.literal("/task-runs") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1505,7 +1579,7 @@ func (c *internalClient) ListCleanRoomTaskRunsHandler(ctx context.Context, req * // // For example: // -// for item, err := range c.ListCleanRoomTaskRunsHandlerIter(ctx, &ListCleanRoomTaskRunsRequest{}) { +// for item, err := range c.ListCleanRoomTaskRunsHandlerIter(ctx, ListCleanRoomTaskRunsRequest{}) { // if err != nil { // return err // } @@ -1517,16 +1591,13 @@ func (c *internalClient) ListCleanRoomTaskRunsHandler(ctx context.Context, req * // // Callers who need custom pagination logic should use // ListCleanRoomTaskRunsHandler directly. -func (c *internalClient) ListCleanRoomTaskRunsHandlerIter(ctx context.Context, req *ListCleanRoomTaskRunsRequest, opts ...call.Option) iter.Seq2[*CleanRoomTaskRun, error] { +func (c *internalClient) ListCleanRoomTaskRunsHandlerIter(ctx context.Context, req ListCleanRoomTaskRunsRequest, opts ...call.Option) iter.Seq2[*CleanRoomTaskRun, error] { return func(yield func(*CleanRoomTaskRun, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListCleanRoomTaskRunsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListCleanRoomTaskRunsHandler(ctx, &pageReq, opts...) + resp, err := c.ListCleanRoomTaskRunsHandler(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1546,8 +1617,8 @@ func (c *internalClient) ListCleanRoomTaskRunsHandlerIter(ctx context.Context, r // Get a list of all clean rooms of the metastore. Only clean rooms the caller // has access to are returned. -func (c *internalClient) ListCleanRooms(ctx context.Context, req *ListCleanRoomsRequest, opts ...call.Option) (*ListCleanRoomsResponse, error) { - wireReq, err := listCleanRoomsRequestToWire(req) +func (c *internalClient) ListCleanRooms(ctx context.Context, req ListCleanRoomsRequest, opts ...call.Option) (*ListCleanRoomsResponse, error) { + wireReq, err := listCleanRoomsRequestToWire(&req) if err != nil { return nil, err } @@ -1617,7 +1688,7 @@ func (c *internalClient) ListCleanRooms(ctx context.Context, req *ListCleanRooms // // For example: // -// for item, err := range c.ListCleanRoomsIter(ctx, &ListCleanRoomsRequest{}) { +// for item, err := range c.ListCleanRoomsIter(ctx, ListCleanRoomsRequest{}) { // if err != nil { // return err // } @@ -1629,16 +1700,13 @@ func (c *internalClient) ListCleanRooms(ctx context.Context, req *ListCleanRooms // // Callers who need custom pagination logic should use // ListCleanRooms directly. -func (c *internalClient) ListCleanRoomsIter(ctx context.Context, req *ListCleanRoomsRequest, opts ...call.Option) iter.Seq2[*CleanRoom, error] { +func (c *internalClient) ListCleanRoomsIter(ctx context.Context, req ListCleanRoomsRequest, opts ...call.Option) iter.Seq2[*CleanRoom, error] { return func(yield func(*CleanRoom, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListCleanRoomsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListCleanRooms(ctx, &pageReq, opts...) + resp, err := c.ListCleanRooms(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1661,8 +1729,8 @@ func (c *internalClient) ListCleanRoomsIter(ctx context.Context, req *ListCleanR // // When the caller is a metastore admin, only the __owner__ field can be // updated. -func (c *internalClient) UpdateCleanRoom(ctx context.Context, req *UpdateCleanRoomRequest, opts ...call.Option) (*CleanRoom, error) { - wireReq, err := updateCleanRoomRequestToWire(req) +func (c *internalClient) UpdateCleanRoom(ctx context.Context, req UpdateCleanRoomRequest, opts ...call.Option) (*CleanRoom, error) { + wireReq, err := updateCleanRoomRequestToWire(&req) if err != nil { return nil, err } @@ -1683,7 +1751,11 @@ func (c *internalClient) UpdateCleanRoom(ctx context.Context, req *UpdateCleanRo } pb := pathBuilder{} pb.literal("/api/2.0/clean-rooms/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1731,8 +1803,8 @@ func (c *internalClient) UpdateCleanRoom(ctx context.Context, req *UpdateCleanRo // Update a clean room asset. For example, updating the content of a notebook; // changing the shared partitions of a table; etc. -func (c *internalClient) UpdateCleanRoomAsset(ctx context.Context, req *UpdateCleanRoomAssetRequest, opts ...call.Option) (*CleanRoomAsset, error) { - wireReq, err := updateCleanRoomAssetRequestToWire(req) +func (c *internalClient) UpdateCleanRoomAsset(ctx context.Context, req UpdateCleanRoomAssetRequest, opts ...call.Option) (*CleanRoomAsset, error) { + wireReq, err := updateCleanRoomAssetRequestToWire(&req) if err != nil { return nil, err } @@ -1751,16 +1823,25 @@ func (c *internalClient) UpdateCleanRoomAsset(ctx context.Context, req *UpdateCl if err != nil { return nil, err } - if req.Asset.AssetType == "" { - return nil, fmt.Errorf("path parameter %q is required", "asset_type") - } pb := pathBuilder{} pb.literal("/api/2.0/clean-rooms/") - pb.singleSegment(*req.CleanRoomName) + if req.CleanRoomName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CleanRoomName) + } pb.literal("/assets/") - pb.singleSegment(req.Asset.AssetType) + if req.Asset == nil { + pb.singleSegment("") + } else { + pb.singleSegment(req.Asset.AssetType) + } pb.literal("/") - pb.singleSegment(*req.Asset.Name) + if req.Asset == nil || req.Asset.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Asset.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1807,8 +1888,8 @@ func (c *internalClient) UpdateCleanRoomAsset(ctx context.Context, req *UpdateCl } // Update a auto-approval rule by rule ID -func (c *internalClient) UpdateCleanRoomAutoApprovalRule(ctx context.Context, req *UpdateCleanRoomAutoApprovalRuleRequest, opts ...call.Option) (*CleanRoomAutoApprovalRule, error) { - wireReq, err := updateCleanRoomAutoApprovalRuleRequestToWire(req) +func (c *internalClient) UpdateCleanRoomAutoApprovalRule(ctx context.Context, req UpdateCleanRoomAutoApprovalRuleRequest, opts ...call.Option) (*CleanRoomAutoApprovalRule, error) { + wireReq, err := updateCleanRoomAutoApprovalRuleRequestToWire(&req) if err != nil { return nil, err } @@ -1829,9 +1910,17 @@ func (c *internalClient) UpdateCleanRoomAutoApprovalRule(ctx context.Context, re } pb := pathBuilder{} pb.literal("/api/2.0/clean-rooms/") - pb.singleSegment(*req.AutoApprovalRule.CleanRoomName) + if req.AutoApprovalRule == nil || req.AutoApprovalRule.CleanRoomName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.AutoApprovalRule.CleanRoomName) + } pb.literal("/auto-approval-rules/") - pb.singleSegment(*req.AutoApprovalRule.RuleId) + if req.AutoApprovalRule == nil || req.AutoApprovalRule.RuleId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.AutoApprovalRule.RuleId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/cleanrooms/v1/genhelper.go b/cleanrooms/v1/genhelper.go old mode 100755 new mode 100644 index f1cd505..e4969fb --- a/cleanrooms/v1/genhelper.go +++ b/cleanrooms/v1/genhelper.go @@ -199,11 +199,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -216,13 +217,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/cleanrooms/v1/model.go b/cleanrooms/v1/model.go old mode 100755 new mode 100644 index 5c56ffb..becd69c --- a/cleanrooms/v1/model.go +++ b/cleanrooms/v1/model.go @@ -351,7 +351,7 @@ type isCleanRoomAsset_LocalDetails interface { // CleanRoomAsset_LocalDetails_TableLocalDetails selects TableLocalDetails for CleanRoomAsset.LocalDetails. // Local details for a table that are only available to its owner. Present if -// and only if **asset_type** is **TABLE** +// and only if **asset_type** is **TABLE** or **STREAMING_TABLE** type CleanRoomAsset_LocalDetails_TableLocalDetails struct { TableLocalDetails CleanRoomAsset_TableLocalDetails } @@ -391,7 +391,7 @@ type isCleanRoomAsset_Details interface { // CleanRoomAsset_Details_Table selects Table for CleanRoomAsset.Details. // Table details available to all collaborators of the clean room. Present if -// and only if **asset_type** is **TABLE** +// and only if **asset_type** is **TABLE** or **STREAMING_TABLE** type CleanRoomAsset_Details_Table struct { Table CleanRoomAsset_Table } @@ -812,10 +812,9 @@ type ColumnMask struct { // column being masked and the types of the rest of the args should match the // types of columns in 'using_column_names'. UsingColumnNames []string - // The list of additional table columns or literals to be passed as additional - // arguments to a column mask function. This is the replacement of the - // deprecated using_column_names field and carries information about the types - // (alias or constant) of the arguments to the mask function. + // The list of table columns or literals to be passed as additional arguments to + // a column mask function, carrying the type (column reference vs constant + // literal) of each argument. Deprecated: use using_column_names instead. UsingArguments []PolicyFunctionArgument } diff --git a/cleanrooms/v1/wire.go b/cleanrooms/v1/wire.go old mode 100755 new mode 100644 index cd190e3..0fa24f5 --- a/cleanrooms/v1/wire.go +++ b/cleanrooms/v1/wire.go @@ -3,16 +3,62 @@ package cleanrooms import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type cleanRoomWire struct { Name *string `json:"name,omitempty"` RemoteDetailedInfo *cleanRoomRemoteDetailWire `json:"remote_detailed_info,omitempty"` Owner *string `json:"owner,omitempty"` Comment *string `json:"comment,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` Status CleanRoom_Status_Enum `json:"status,omitempty"` LocalCollaboratorAlias *string `json:"local_collaborator_alias,omitempty"` OutputCatalog *cleanRoomOutputCatalogWire `json:"output_catalog,omitempty"` @@ -28,6 +74,14 @@ func cleanRoomToWire(v *CleanRoom) (*cleanRoomWire, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "CleanRoom.RemoteDetailedInfo", err) } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoom.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoom.UpdatedAt", err) + } outputCatalogWireValue, err := cleanRoomOutputCatalogToWire(v.OutputCatalog) if err != nil { return nil, fmt.Errorf("%s: %w", "CleanRoom.OutputCatalog", err) @@ -37,8 +91,8 @@ func cleanRoomToWire(v *CleanRoom) (*cleanRoomWire, error) { RemoteDetailedInfo: remoteDetailedInfoWireValue, Owner: v.Owner, Comment: v.Comment, - CreatedAt: v.CreatedAt, - UpdatedAt: v.UpdatedAt, + CreatedAt: createdAtWireValue, + UpdatedAt: updatedAtWireValue, Status: v.Status, LocalCollaboratorAlias: v.LocalCollaboratorAlias, OutputCatalog: outputCatalogWireValue, @@ -55,6 +109,14 @@ func cleanRoomFromWire(w *cleanRoomWire) (*CleanRoom, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "CleanRoom.RemoteDetailedInfo", err) } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoom.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoom.UpdatedAt", err) + } outputCatalogPublicValue, err := cleanRoomOutputCatalogFromWire(w.OutputCatalog) if err != nil { return nil, fmt.Errorf("%s: %w", "CleanRoom.OutputCatalog", err) @@ -64,8 +126,8 @@ func cleanRoomFromWire(w *cleanRoomWire) (*CleanRoom, error) { RemoteDetailedInfo: remoteDetailedInfoPublicValue, Owner: w.Owner, Comment: w.Comment, - CreatedAt: w.CreatedAt, - UpdatedAt: w.UpdatedAt, + CreatedAt: createdAtPublicValue, + UpdatedAt: updatedAtPublicValue, Status: w.Status, LocalCollaboratorAlias: w.LocalCollaboratorAlias, OutputCatalog: outputCatalogPublicValue, @@ -78,7 +140,7 @@ type cleanRoomAssetWire struct { CleanRoomName *string `json:"clean_room_name,omitempty"` Name *string `json:"name,omitempty"` AssetType CleanRoomAsset_AssetType `json:"asset_type,omitempty"` - AddedAt *int64 `json:"added_at,omitempty"` + AddedAt *wireInt64 `json:"added_at,omitempty"` Status CleanRoomAsset_Status_Enum `json:"status,omitempty"` OwnerCollaboratorAlias *string `json:"owner_collaborator_alias,omitempty"` TableLocalDetails *cleanRoomAsset_TableLocalDetailsWire `json:"table_local_details,omitempty"` @@ -96,6 +158,10 @@ func cleanRoomAssetToWire(v *CleanRoomAsset) (*cleanRoomAssetWire, error) { if v == nil { return nil, nil } + addedAtWireValue, err := int64ToWire(v.AddedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoomAsset.AddedAt", err) + } var localDetailsTableLocalDetailsWire *cleanRoomAsset_TableLocalDetailsWire var localDetailsVolumeLocalDetailsWire *cleanRoomAsset_VolumeLocalDetailsWire var localDetailsViewLocalDetailsWire *cleanRoomAsset_ViewLocalDetailsWire @@ -191,7 +257,7 @@ func cleanRoomAssetToWire(v *CleanRoomAsset) (*cleanRoomAssetWire, error) { CleanRoomName: v.CleanRoomName, Name: v.Name, AssetType: v.AssetType, - AddedAt: v.AddedAt, + AddedAt: addedAtWireValue, Status: v.Status, OwnerCollaboratorAlias: v.OwnerCollaboratorAlias, TableLocalDetails: localDetailsTableLocalDetailsWire, @@ -245,6 +311,10 @@ func cleanRoomAssetFromWire(w *cleanRoomAssetWire) (*CleanRoomAsset, error) { if detailsMembers > 1 { return nil, fmt.Errorf("%s: multiple oneof members set", "CleanRoomAsset.Details") } + addedAtPublicValue, err := int64FromWire(w.AddedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoomAsset.AddedAt", err) + } var localDetailsSelection isCleanRoomAsset_LocalDetails switch { case w.TableLocalDetails != nil: @@ -309,7 +379,7 @@ func cleanRoomAssetFromWire(w *cleanRoomAssetWire) (*CleanRoomAsset, error) { CleanRoomName: w.CleanRoomName, Name: w.Name, AssetType: w.AssetType, - AddedAt: w.AddedAt, + AddedAt: addedAtPublicValue, Status: w.Status, OwnerCollaboratorAlias: w.OwnerCollaboratorAlias, LocalDetails: localDetailsSelection, @@ -612,13 +682,17 @@ type cleanRoomAutoApprovalRuleWire struct { AuthorCollaboratorAlias *string `json:"author_collaborator_alias,omitempty"` AuthorScope CleanRoomAutoApprovalRule_AuthorScope `json:"author_scope,omitempty"` RunnerCollaboratorAlias *string `json:"runner_collaborator_alias,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` } func cleanRoomAutoApprovalRuleToWire(v *CleanRoomAutoApprovalRule) (*cleanRoomAutoApprovalRuleWire, error) { if v == nil { return nil, nil } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoomAutoApprovalRule.CreatedAt", err) + } var authorsAuthorCollaboratorAliasWire *string var authorsAuthorScopeWire CleanRoomAutoApprovalRule_AuthorScope switch value := v.Authors.(type) { @@ -651,7 +725,7 @@ func cleanRoomAutoApprovalRuleToWire(v *CleanRoomAutoApprovalRule) (*cleanRoomAu AuthorCollaboratorAlias: authorsAuthorCollaboratorAliasWire, AuthorScope: authorsAuthorScopeWire, RunnerCollaboratorAlias: runnersRunnerCollaboratorAliasWire, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, }, nil } @@ -676,6 +750,10 @@ func cleanRoomAutoApprovalRuleFromWire(w *cleanRoomAutoApprovalRuleWire) (*Clean if runnersMembers > 1 { return nil, fmt.Errorf("%s: multiple oneof members set", "CleanRoomAutoApprovalRule.Runners") } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoomAutoApprovalRule.CreatedAt", err) + } var authorsSelection isCleanRoomAutoApprovalRule_Authors switch { case w.AuthorCollaboratorAlias != nil: @@ -692,29 +770,33 @@ func cleanRoomAutoApprovalRuleFromWire(w *cleanRoomAutoApprovalRuleWire) (*Clean CleanRoomName: w.CleanRoomName, RuleId: w.RuleId, RuleOwnerCollaboratorAlias: w.RuleOwnerCollaboratorAlias, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, Authors: authorsSelection, Runners: runnersSelection, }, nil } type cleanRoomCollaboratorWire struct { - GlobalMetastoreId *string `json:"global_metastore_id,omitempty"` - OrganizationName *string `json:"organization_name,omitempty"` - InviteRecipientWorkspaceId *int64 `json:"invite_recipient_workspace_id,omitempty"` - InviteRecipientEmail *string `json:"invite_recipient_email,omitempty"` - CollaboratorAlias *string `json:"collaborator_alias,omitempty"` - DisplayName *string `json:"display_name,omitempty"` + GlobalMetastoreId *string `json:"global_metastore_id,omitempty"` + OrganizationName *string `json:"organization_name,omitempty"` + InviteRecipientWorkspaceId *wireInt64 `json:"invite_recipient_workspace_id,omitempty"` + InviteRecipientEmail *string `json:"invite_recipient_email,omitempty"` + CollaboratorAlias *string `json:"collaborator_alias,omitempty"` + DisplayName *string `json:"display_name,omitempty"` } func cleanRoomCollaboratorToWire(v *CleanRoomCollaborator) (*cleanRoomCollaboratorWire, error) { if v == nil { return nil, nil } + inviteRecipientWorkspaceIdWireValue, err := int64ToWire(v.InviteRecipientWorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoomCollaborator.InviteRecipientWorkspaceId", err) + } return &cleanRoomCollaboratorWire{ GlobalMetastoreId: v.GlobalMetastoreId, OrganizationName: v.OrganizationName, - InviteRecipientWorkspaceId: v.InviteRecipientWorkspaceId, + InviteRecipientWorkspaceId: inviteRecipientWorkspaceIdWireValue, InviteRecipientEmail: v.InviteRecipientEmail, CollaboratorAlias: v.CollaboratorAlias, DisplayName: v.DisplayName, @@ -725,10 +807,14 @@ func cleanRoomCollaboratorFromWire(w *cleanRoomCollaboratorWire) (*CleanRoomColl if w == nil { return nil, nil } + inviteRecipientWorkspaceIdPublicValue, err := int64FromWire(w.InviteRecipientWorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoomCollaborator.InviteRecipientWorkspaceId", err) + } return &CleanRoomCollaborator{ GlobalMetastoreId: w.GlobalMetastoreId, OrganizationName: w.OrganizationName, - InviteRecipientWorkspaceId: w.InviteRecipientWorkspaceId, + InviteRecipientWorkspaceId: inviteRecipientWorkspaceIdPublicValue, InviteRecipientEmail: w.InviteRecipientEmail, CollaboratorAlias: w.CollaboratorAlias, DisplayName: w.DisplayName, @@ -737,7 +823,7 @@ func cleanRoomCollaboratorFromWire(w *cleanRoomCollaboratorWire) (*CleanRoomColl type cleanRoomJarAnalysisReviewWire struct { ReviewerCollaboratorAlias *string `json:"reviewer_collaborator_alias,omitempty"` - CreatedAtMillis *int64 `json:"created_at_millis,omitempty"` + CreatedAtMillis *wireInt64 `json:"created_at_millis,omitempty"` ReviewState CleanRoomJarAnalysisReview_JarAnalysisReviewState `json:"review_state,omitempty"` Comment *string `json:"comment,omitempty"` ReviewSubReason CleanRoomJarAnalysisReview_JarAnalysisReviewSubReason `json:"review_sub_reason,omitempty"` @@ -747,9 +833,13 @@ func cleanRoomJarAnalysisReviewToWire(v *CleanRoomJarAnalysisReview) (*cleanRoom if v == nil { return nil, nil } + createdAtMillisWireValue, err := int64ToWire(v.CreatedAtMillis) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoomJarAnalysisReview.CreatedAtMillis", err) + } return &cleanRoomJarAnalysisReviewWire{ ReviewerCollaboratorAlias: v.ReviewerCollaboratorAlias, - CreatedAtMillis: v.CreatedAtMillis, + CreatedAtMillis: createdAtMillisWireValue, ReviewState: v.ReviewState, Comment: v.Comment, ReviewSubReason: v.ReviewSubReason, @@ -760,9 +850,13 @@ func cleanRoomJarAnalysisReviewFromWire(w *cleanRoomJarAnalysisReviewWire) (*Cle if w == nil { return nil, nil } + createdAtMillisPublicValue, err := int64FromWire(w.CreatedAtMillis) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoomJarAnalysisReview.CreatedAtMillis", err) + } return &CleanRoomJarAnalysisReview{ ReviewerCollaboratorAlias: w.ReviewerCollaboratorAlias, - CreatedAtMillis: w.CreatedAtMillis, + CreatedAtMillis: createdAtMillisPublicValue, ReviewState: w.ReviewState, Comment: w.Comment, ReviewSubReason: w.ReviewSubReason, @@ -771,7 +865,7 @@ func cleanRoomJarAnalysisReviewFromWire(w *cleanRoomJarAnalysisReviewWire) (*Cle type cleanRoomNotebookReviewWire struct { ReviewerCollaboratorAlias *string `json:"reviewer_collaborator_alias,omitempty"` - CreatedAtMillis *int64 `json:"created_at_millis,omitempty"` + CreatedAtMillis *wireInt64 `json:"created_at_millis,omitempty"` ReviewState CleanRoomNotebookReview_NotebookReviewState `json:"review_state,omitempty"` Comment *string `json:"comment,omitempty"` ReviewSubReason CleanRoomNotebookReview_NotebookReviewSubReason `json:"review_sub_reason,omitempty"` @@ -781,9 +875,13 @@ func cleanRoomNotebookReviewToWire(v *CleanRoomNotebookReview) (*cleanRoomNotebo if v == nil { return nil, nil } + createdAtMillisWireValue, err := int64ToWire(v.CreatedAtMillis) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoomNotebookReview.CreatedAtMillis", err) + } return &cleanRoomNotebookReviewWire{ ReviewerCollaboratorAlias: v.ReviewerCollaboratorAlias, - CreatedAtMillis: v.CreatedAtMillis, + CreatedAtMillis: createdAtMillisWireValue, ReviewState: v.ReviewState, Comment: v.Comment, ReviewSubReason: v.ReviewSubReason, @@ -794,9 +892,13 @@ func cleanRoomNotebookReviewFromWire(w *cleanRoomNotebookReviewWire) (*CleanRoom if w == nil { return nil, nil } + createdAtMillisPublicValue, err := int64FromWire(w.CreatedAtMillis) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoomNotebookReview.CreatedAtMillis", err) + } return &CleanRoomNotebookReview{ ReviewerCollaboratorAlias: w.ReviewerCollaboratorAlias, - CreatedAtMillis: w.CreatedAtMillis, + CreatedAtMillis: createdAtMillisPublicValue, ReviewState: w.ReviewState, Comment: w.Comment, ReviewSubReason: w.ReviewSubReason, @@ -805,22 +907,30 @@ func cleanRoomNotebookReviewFromWire(w *cleanRoomNotebookReviewWire) (*CleanRoom type cleanRoomNotebookTaskRunWire struct { NotebookName *string `json:"notebook_name,omitempty"` - StartTime *int64 `json:"start_time,omitempty"` - RunDuration *int64 `json:"run_duration,omitempty"` + StartTime *wireInt64 `json:"start_time,omitempty"` + RunDuration *wireInt64 `json:"run_duration,omitempty"` NotebookJobRunState *cleanRoomTaskRunStateWire `json:"notebook_job_run_state,omitempty"` CollaboratorJobRunInfo *collaboratorJobRunInfoWire `json:"collaborator_job_run_info,omitempty"` OutputSchemaName *string `json:"output_schema_name,omitempty"` - OutputSchemaExpirationTime *int64 `json:"output_schema_expiration_time,omitempty"` + OutputSchemaExpirationTime *wireInt64 `json:"output_schema_expiration_time,omitempty"` NotebookEtag *string `json:"notebook_etag,omitempty"` - NotebookUpdatedAt *int64 `json:"notebook_updated_at,omitempty"` + NotebookUpdatedAt *wireInt64 `json:"notebook_updated_at,omitempty"` SharedOutputSchemaName *string `json:"shared_output_schema_name,omitempty"` - SharedOutputSchemaExpirationTime *int64 `json:"shared_output_schema_expiration_time,omitempty"` + SharedOutputSchemaExpirationTime *wireInt64 `json:"shared_output_schema_expiration_time,omitempty"` } func cleanRoomNotebookTaskRunFromWire(w *cleanRoomNotebookTaskRunWire) (*CleanRoomNotebookTaskRun, error) { if w == nil { return nil, nil } + startTimePublicValue, err := int64FromWire(w.StartTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoomNotebookTaskRun.StartTime", err) + } + runDurationPublicValue, err := int64FromWire(w.RunDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoomNotebookTaskRun.RunDuration", err) + } notebookJobRunStatePublicValue, err := cleanRoomTaskRunStateFromWire(w.NotebookJobRunState) if err != nil { return nil, fmt.Errorf("%s: %w", "CleanRoomNotebookTaskRun.NotebookJobRunState", err) @@ -829,18 +939,30 @@ func cleanRoomNotebookTaskRunFromWire(w *cleanRoomNotebookTaskRunWire) (*CleanRo if err != nil { return nil, fmt.Errorf("%s: %w", "CleanRoomNotebookTaskRun.CollaboratorJobRunInfo", err) } + outputSchemaExpirationTimePublicValue, err := int64FromWire(w.OutputSchemaExpirationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoomNotebookTaskRun.OutputSchemaExpirationTime", err) + } + notebookUpdatedAtPublicValue, err := int64FromWire(w.NotebookUpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoomNotebookTaskRun.NotebookUpdatedAt", err) + } + sharedOutputSchemaExpirationTimePublicValue, err := int64FromWire(w.SharedOutputSchemaExpirationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoomNotebookTaskRun.SharedOutputSchemaExpirationTime", err) + } return &CleanRoomNotebookTaskRun{ NotebookName: w.NotebookName, - StartTime: w.StartTime, - RunDuration: w.RunDuration, + StartTime: startTimePublicValue, + RunDuration: runDurationPublicValue, NotebookJobRunState: notebookJobRunStatePublicValue, CollaboratorJobRunInfo: collaboratorJobRunInfoPublicValue, OutputSchemaName: w.OutputSchemaName, - OutputSchemaExpirationTime: w.OutputSchemaExpirationTime, + OutputSchemaExpirationTime: outputSchemaExpirationTimePublicValue, NotebookEtag: w.NotebookEtag, - NotebookUpdatedAt: w.NotebookUpdatedAt, + NotebookUpdatedAt: notebookUpdatedAtPublicValue, SharedOutputSchemaName: w.SharedOutputSchemaName, - SharedOutputSchemaExpirationTime: w.SharedOutputSchemaExpirationTime, + SharedOutputSchemaExpirationTime: sharedOutputSchemaExpirationTimePublicValue, }, nil } @@ -950,8 +1072,8 @@ func cleanRoomRemoteDetailFromWire(w *cleanRoomRemoteDetailWire) (*CleanRoomRemo type cleanRoomTaskRunWire struct { Name *string `json:"name,omitempty"` TaskType CleanRoomTaskType `json:"task_type,omitempty"` - StartTime *int64 `json:"start_time,omitempty"` - RunDuration *int64 `json:"run_duration,omitempty"` + StartTime *wireInt64 `json:"start_time,omitempty"` + RunDuration *wireInt64 `json:"run_duration,omitempty"` TaskRunState *cleanRoomTaskRunStateWire `json:"task_run_state,omitempty"` CollaboratorJobRunInfo *collaboratorJobRunInfoWire `json:"collaborator_job_run_info,omitempty"` OutputInfo *cleanRoomTaskRun_OutputInfoWire `json:"output_info,omitempty"` @@ -963,6 +1085,14 @@ func cleanRoomTaskRunFromWire(w *cleanRoomTaskRunWire) (*CleanRoomTaskRun, error if w == nil { return nil, nil } + startTimePublicValue, err := int64FromWire(w.StartTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoomTaskRun.StartTime", err) + } + runDurationPublicValue, err := int64FromWire(w.RunDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoomTaskRun.RunDuration", err) + } taskRunStatePublicValue, err := cleanRoomTaskRunStateFromWire(w.TaskRunState) if err != nil { return nil, fmt.Errorf("%s: %w", "CleanRoomTaskRun.TaskRunState", err) @@ -986,8 +1116,8 @@ func cleanRoomTaskRunFromWire(w *cleanRoomTaskRunWire) (*CleanRoomTaskRun, error return &CleanRoomTaskRun{ Name: w.Name, TaskType: w.TaskType, - StartTime: w.StartTime, - RunDuration: w.RunDuration, + StartTime: startTimePublicValue, + RunDuration: runDurationPublicValue, TaskRunState: taskRunStatePublicValue, CollaboratorJobRunInfo: collaboratorJobRunInfoPublicValue, OutputInfo: outputInfoPublicValue, @@ -997,32 +1127,40 @@ func cleanRoomTaskRunFromWire(w *cleanRoomTaskRunWire) (*CleanRoomTaskRun, error } type cleanRoomTaskRun_CleanRoomTaskAnalysisDetailsWire struct { - Etag *string `json:"etag,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + Etag *string `json:"etag,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` } func cleanRoomTaskRun_CleanRoomTaskAnalysisDetailsFromWire(w *cleanRoomTaskRun_CleanRoomTaskAnalysisDetailsWire) (*CleanRoomTaskRun_CleanRoomTaskAnalysisDetails, error) { if w == nil { return nil, nil } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoomTaskRun_CleanRoomTaskAnalysisDetails.UpdatedAt", err) + } return &CleanRoomTaskRun_CleanRoomTaskAnalysisDetails{ Etag: w.Etag, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, }, nil } type cleanRoomTaskRun_OutputInfoWire struct { - OutputSchemaName *string `json:"output_schema_name,omitempty"` - OutputSchemaExpirationTime *int64 `json:"output_schema_expiration_time,omitempty"` + OutputSchemaName *string `json:"output_schema_name,omitempty"` + OutputSchemaExpirationTime *wireInt64 `json:"output_schema_expiration_time,omitempty"` } func cleanRoomTaskRun_OutputInfoFromWire(w *cleanRoomTaskRun_OutputInfoWire) (*CleanRoomTaskRun_OutputInfo, error) { if w == nil { return nil, nil } + outputSchemaExpirationTimePublicValue, err := int64FromWire(w.OutputSchemaExpirationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CleanRoomTaskRun_OutputInfo.OutputSchemaExpirationTime", err) + } return &CleanRoomTaskRun_OutputInfo{ OutputSchemaName: w.OutputSchemaName, - OutputSchemaExpirationTime: w.OutputSchemaExpirationTime, + OutputSchemaExpirationTime: outputSchemaExpirationTimePublicValue, }, nil } @@ -1042,22 +1180,38 @@ func cleanRoomTaskRunStateFromWire(w *cleanRoomTaskRunStateWire) (*CleanRoomTask } type collaboratorJobRunInfoWire struct { - CollaboratorJobId *int64 `json:"collaborator_job_id,omitempty"` - CollaboratorJobRunId *int64 `json:"collaborator_job_run_id,omitempty"` - CollaboratorTaskRunId *int64 `json:"collaborator_task_run_id,omitempty"` - CollaboratorWorkspaceId *int64 `json:"collaborator_workspace_id,omitempty"` - CollaboratorAlias *string `json:"collaborator_alias,omitempty"` + CollaboratorJobId *wireInt64 `json:"collaborator_job_id,omitempty"` + CollaboratorJobRunId *wireInt64 `json:"collaborator_job_run_id,omitempty"` + CollaboratorTaskRunId *wireInt64 `json:"collaborator_task_run_id,omitempty"` + CollaboratorWorkspaceId *wireInt64 `json:"collaborator_workspace_id,omitempty"` + CollaboratorAlias *string `json:"collaborator_alias,omitempty"` } func collaboratorJobRunInfoFromWire(w *collaboratorJobRunInfoWire) (*CollaboratorJobRunInfo, error) { if w == nil { return nil, nil } + collaboratorJobIdPublicValue, err := int64FromWire(w.CollaboratorJobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CollaboratorJobRunInfo.CollaboratorJobId", err) + } + collaboratorJobRunIdPublicValue, err := int64FromWire(w.CollaboratorJobRunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CollaboratorJobRunInfo.CollaboratorJobRunId", err) + } + collaboratorTaskRunIdPublicValue, err := int64FromWire(w.CollaboratorTaskRunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CollaboratorJobRunInfo.CollaboratorTaskRunId", err) + } + collaboratorWorkspaceIdPublicValue, err := int64FromWire(w.CollaboratorWorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CollaboratorJobRunInfo.CollaboratorWorkspaceId", err) + } return &CollaboratorJobRunInfo{ - CollaboratorJobId: w.CollaboratorJobId, - CollaboratorJobRunId: w.CollaboratorJobRunId, - CollaboratorTaskRunId: w.CollaboratorTaskRunId, - CollaboratorWorkspaceId: w.CollaboratorWorkspaceId, + CollaboratorJobId: collaboratorJobIdPublicValue, + CollaboratorJobRunId: collaboratorJobRunIdPublicValue, + CollaboratorTaskRunId: collaboratorTaskRunIdPublicValue, + CollaboratorWorkspaceId: collaboratorWorkspaceIdPublicValue, CollaboratorAlias: w.CollaboratorAlias, }, nil } diff --git a/clusterlibraries/CHANGELOG.md b/clusterlibraries/CHANGELOG.md index 6224c04..19f237c 100644 --- a/clusterlibraries/CHANGELOG.md +++ b/clusterlibraries/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/clusterlibraries/go.mod b/clusterlibraries/go.mod index e3ec4b3..c18064a 100644 --- a/clusterlibraries/go.mod +++ b/clusterlibraries/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/clusterlibraries/internal/version.go b/clusterlibraries/internal/version.go index 1996c7b..e4e565b 100644 --- a/clusterlibraries/internal/version.go +++ b/clusterlibraries/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-clusterlibraries" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/clusterlibraries/v2/client.go b/clusterlibraries/v2/client.go old mode 100755 new mode 100644 index ac839c3..8eba57b --- a/clusterlibraries/v2/client.go +++ b/clusterlibraries/v2/client.go @@ -75,7 +75,7 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Get the status of all libraries on all clusters. A status is returned for all // libraries installed on this cluster via the API or the libraries UI. -func (c *internalClient) AllClusterStatuses(ctx context.Context, req *ListAllClusterLibraryStatusesRequest, opts ...call.Option) (*ListAllClusterLibraryStatusesResponse, error) { +func (c *internalClient) AllClusterStatuses(ctx context.Context, req ListAllClusterLibraryStatusesRequest, opts ...call.Option) (*ListAllClusterLibraryStatusesResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -138,8 +138,8 @@ func (c *internalClient) AllClusterStatuses(ctx context.Context, req *ListAllClu // are returned first. 2. Libraries that were previously requested to be // installed on this cluster or, but are now marked for removal, in no // particular order, are returned last. -func (c *internalClient) ClusterStatus(ctx context.Context, req *ClusterStatusRequest, opts ...call.Option) (*ClusterLibraryStatuses, error) { - wireReq, err := clusterStatusRequestToWire(req) +func (c *internalClient) ClusterStatus(ctx context.Context, req ClusterStatusRequest, opts ...call.Option) (*ClusterLibraryStatuses, error) { + wireReq, err := clusterStatusRequestToWire(&req) if err != nil { return nil, err } @@ -203,8 +203,8 @@ func (c *internalClient) ClusterStatus(ctx context.Context, req *ClusterStatusRe // Add libraries to install on a cluster. The installation is asynchronous; it // happens in the background after the completion of this request. -func (c *internalClient) InstallLibraries(ctx context.Context, req *InstallLibrariesRequest, opts ...call.Option) (*InstallLibrariesResponse, error) { - wireReq, err := installLibrariesRequestToWire(req) +func (c *internalClient) InstallLibraries(ctx context.Context, req InstallLibrariesRequest, opts ...call.Option) (*InstallLibrariesResponse, error) { + wireReq, err := installLibrariesRequestToWire(&req) if err != nil { return nil, err } @@ -265,8 +265,8 @@ func (c *internalClient) InstallLibraries(ctx context.Context, req *InstallLibra // Set libraries to uninstall from a cluster. The libraries won't be uninstalled // until the cluster is restarted. A request to uninstall a library that is not // currently installed is ignored. -func (c *internalClient) UninstallLibraries(ctx context.Context, req *UninstallLibrariesRequest, opts ...call.Option) (*UninstallLibrariesResponse, error) { - wireReq, err := uninstallLibrariesRequestToWire(req) +func (c *internalClient) UninstallLibraries(ctx context.Context, req UninstallLibrariesRequest, opts ...call.Option) (*UninstallLibrariesResponse, error) { + wireReq, err := uninstallLibrariesRequestToWire(&req) if err != nil { return nil, err } diff --git a/clusterpolicies/CHANGELOG.md b/clusterpolicies/CHANGELOG.md index 6224c04..19f237c 100644 --- a/clusterpolicies/CHANGELOG.md +++ b/clusterpolicies/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/clusterpolicies/go.mod b/clusterpolicies/go.mod index 3be3a99..0b7a4e7 100644 --- a/clusterpolicies/go.mod +++ b/clusterpolicies/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/clusterpolicies/internal/version.go b/clusterpolicies/internal/version.go index 7782184..71df4c4 100644 --- a/clusterpolicies/internal/version.go +++ b/clusterpolicies/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-clusterpolicies" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/clusterpolicies/v2/client.go b/clusterpolicies/v2/client.go old mode 100755 new mode 100644 index 31b9385..756d6dc --- a/clusterpolicies/v2/client.go +++ b/clusterpolicies/v2/client.go @@ -6,7 +6,6 @@ import ( "bytes" "context" "encoding/json" - "iter" "log/slog" "net/http" "net/url" @@ -74,254 +73,9 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { }, nil } -// Get details of a cluster policy revision. -func (c *internalClient) GetClusterPolicyRevision(ctx context.Context, req *GetClusterPolicyRevisionRequest, opts ...call.Option) (*ClusterPolicyRevision, error) { - - headers := http.Header{} - headers.Set("Content-Type", "application/json") - if c.workspaceID != "" { - headers.Set("X-Databricks-Workspace-Id", c.workspaceID) - } - - baseURL, err := url.Parse(c.host) - if err != nil { - return nil, err - } - pb := pathBuilder{} - pb.literal("/api/2.0/") - pb.singleSegment(*req.Name) - baseURL.Path, baseURL.RawPath = pb.build() - queryParams := url.Values{} - baseURL.RawQuery = queryParams.Encode() - urlStr := baseURL.String() - - var resp *ClusterPolicyRevision - - call := func(ctx context.Context) error { - httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ - Method: "GET", - URL: urlStr, - Credentials: c.credentials, - UserAgent: c.userAgent, - Headers: headers, - }) - if err != nil { - return err - } - - respBody, _, err := executeHTTPCall(httpCallOptions{ - req: httpReq, - client: c.httpClient, - logger: c.logger, - }) - if err != nil { - return err - } - var wireResp clusterPolicyRevisionWire - if err := json.Unmarshal(respBody, &wireResp); err != nil { - return err - } - resp, err = clusterPolicyRevisionFromWire(&wireResp) - if err != nil { - return err - } - return nil - } - - if err := executeCall(ctx, call, opts); err != nil { - return nil, err - } - return resp, nil -} - -// Lists a cluster policy's revisions, ordered from most to least recent. -func (c *internalClient) ListClusterPolicyRevisions(ctx context.Context, req *ListClusterPolicyRevisionsRequest, opts ...call.Option) (*ListClusterPolicyRevisionsResponse, error) { - wireReq, err := listClusterPolicyRevisionsRequestToWire(req) - if err != nil { - return nil, err - } - - headers := http.Header{} - headers.Set("Content-Type", "application/json") - if c.workspaceID != "" { - headers.Set("X-Databricks-Workspace-Id", c.workspaceID) - } - - baseURL, err := url.Parse(c.host) - if err != nil { - return nil, err - } - pb := pathBuilder{} - pb.literal("/api/2.0/") - pb.singleSegment(*req.Parent) - pb.literal("/revisions") - baseURL.Path, baseURL.RawPath = pb.build() - queryParams := url.Values{} - if err := addQueryValue(queryParams, "page_size", wireReq.PageSize); err != nil { - return nil, err - } - if err := addQueryValue(queryParams, "page_token", wireReq.PageToken); err != nil { - return nil, err - } - baseURL.RawQuery = queryParams.Encode() - urlStr := baseURL.String() - - var resp *ListClusterPolicyRevisionsResponse - - call := func(ctx context.Context) error { - httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ - Method: "GET", - URL: urlStr, - Credentials: c.credentials, - UserAgent: c.userAgent, - Headers: headers, - }) - if err != nil { - return err - } - - respBody, _, err := executeHTTPCall(httpCallOptions{ - req: httpReq, - client: c.httpClient, - logger: c.logger, - }) - if err != nil { - return err - } - var wireResp listClusterPolicyRevisionsResponseWire - if err := json.Unmarshal(respBody, &wireResp); err != nil { - return err - } - resp, err = listClusterPolicyRevisionsResponseFromWire(&wireResp) - if err != nil { - return err - } - return nil - } - - if err := executeCall(ctx, call, opts); err != nil { - return nil, err - } - return resp, nil -} - -// ListClusterPolicyRevisionsIter returns an iterator that iterates -// over the results of ListClusterPolicyRevisions. -// -// For example: -// -// for item, err := range c.ListClusterPolicyRevisionsIter(ctx, &ListClusterPolicyRevisionsRequest{}) { -// if err != nil { -// return err -// } -// fmt.Println(item) -// } -// -// Options opts are passed to each ListClusterPolicyRevisions call -// made by the iterator under the hood. -// -// Callers who need custom pagination logic should use -// ListClusterPolicyRevisions directly. -func (c *internalClient) ListClusterPolicyRevisionsIter(ctx context.Context, req *ListClusterPolicyRevisionsRequest, opts ...call.Option) iter.Seq2[*ClusterPolicyRevision, error] { - return func(yield func(*ClusterPolicyRevision, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListClusterPolicyRevisionsRequest{} - if req != nil { - pageReq = *req - } - for { - resp, err := c.ListClusterPolicyRevisions(ctx, &pageReq, opts...) - if err != nil { - yield(nil, err) - return - } - for i := range resp.ClusterPolicyRevisions { - if !yield(&resp.ClusterPolicyRevisions[i], nil) { - return - } - } - if resp.NextPageToken == nil || *resp.NextPageToken == "" { - return - } - pageReq.PageToken = resp.NextPageToken - } - } -} - -// Rolls back a cluster policy to a previous revision. -func (c *internalClient) RollbackClusterPolicy(ctx context.Context, req *RollbackClusterPolicyRequest, opts ...call.Option) (*ClusterPolicyRevision, error) { - wireReq, err := rollbackClusterPolicyRequestToWire(req) - if err != nil { - return nil, err - } - body, err := json.Marshal(wireReq) - if err != nil { - return nil, err - } - - headers := http.Header{} - headers.Set("Content-Type", "application/json") - if c.workspaceID != "" { - headers.Set("X-Databricks-Workspace-Id", c.workspaceID) - } - - baseURL, err := url.Parse(c.host) - if err != nil { - return nil, err - } - pb := pathBuilder{} - pb.literal("/api/2.0/") - pb.singleSegment(*req.Name) - pb.literal("/rollback") - baseURL.Path, baseURL.RawPath = pb.build() - queryParams := url.Values{} - baseURL.RawQuery = queryParams.Encode() - urlStr := baseURL.String() - - var resp *ClusterPolicyRevision - - call := func(ctx context.Context) error { - httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ - Method: "POST", - URL: urlStr, - Credentials: c.credentials, - UserAgent: c.userAgent, - Headers: headers, - Body: bytes.NewBuffer(body), - }) - if err != nil { - return err - } - - respBody, _, err := executeHTTPCall(httpCallOptions{ - req: httpReq, - client: c.httpClient, - logger: c.logger, - }) - if err != nil { - return err - } - var wireResp clusterPolicyRevisionWire - if err := json.Unmarshal(respBody, &wireResp); err != nil { - return err - } - resp, err = clusterPolicyRevisionFromWire(&wireResp) - if err != nil { - return err - } - return nil - } - - if err := executeCall(ctx, call, opts); err != nil { - return nil, err - } - return resp, nil -} - // Creates a new policy with prescribed settings. -func (c *internalClient) CreatePolicy(ctx context.Context, req *CreatePolicyRequest, opts ...call.Option) (*CreatePolicyResponse, error) { - wireReq, err := createPolicyRequestToWire(req) +func (c *internalClient) CreatePolicy(ctx context.Context, req CreatePolicyRequest, opts ...call.Option) (*CreatePolicyResponse, error) { + wireReq, err := createPolicyRequestToWire(&req) if err != nil { return nil, err } @@ -387,8 +141,8 @@ func (c *internalClient) CreatePolicy(ctx context.Context, req *CreatePolicyRequ // Delete a policy for a cluster. Clusters governed by this policy can still // run, but cannot be edited. -func (c *internalClient) DeletePolicy(ctx context.Context, req *DeletePolicyRequest, opts ...call.Option) (*DeletePolicyResponse, error) { - wireReq, err := deletePolicyRequestToWire(req) +func (c *internalClient) DeletePolicy(ctx context.Context, req DeletePolicyRequest, opts ...call.Option) (*DeletePolicyResponse, error) { + wireReq, err := deletePolicyRequestToWire(&req) if err != nil { return nil, err } @@ -448,8 +202,8 @@ func (c *internalClient) DeletePolicy(ctx context.Context, req *DeletePolicyRequ // Update an existing policy for cluster. This operation may make some clusters // governed by the previous policy invalid. -func (c *internalClient) EditPolicy(ctx context.Context, req *EditPolicyRequest, opts ...call.Option) (*EditPolicyResponse, error) { - wireReq, err := editPolicyRequestToWire(req) +func (c *internalClient) EditPolicy(ctx context.Context, req EditPolicyRequest, opts ...call.Option) (*EditPolicyResponse, error) { + wireReq, err := editPolicyRequestToWire(&req) if err != nil { return nil, err } @@ -509,8 +263,8 @@ func (c *internalClient) EditPolicy(ctx context.Context, req *EditPolicyRequest, // Get a cluster policy entity. Creation and editing is available to admins // only. -func (c *internalClient) GetPolicy(ctx context.Context, req *GetPolicyRequest, opts ...call.Option) (*Policy, error) { - wireReq, err := getPolicyRequestToWire(req) +func (c *internalClient) GetPolicy(ctx context.Context, req GetPolicyRequest, opts ...call.Option) (*Policy, error) { + wireReq, err := getPolicyRequestToWire(&req) if err != nil { return nil, err } @@ -573,8 +327,8 @@ func (c *internalClient) GetPolicy(ctx context.Context, req *GetPolicyRequest, o } // Returns a list of policies accessible by the requesting user. -func (c *internalClient) ListPolicies(ctx context.Context, req *ListPoliciesRequest, opts ...call.Option) (*ListPoliciesResponse, error) { - wireReq, err := listPoliciesRequestToWire(req) +func (c *internalClient) ListPolicies(ctx context.Context, req ListPoliciesRequest, opts ...call.Option) (*ListPoliciesResponse, error) { + wireReq, err := listPoliciesRequestToWire(&req) if err != nil { return nil, err } diff --git a/clusterpolicies/v2/genhelper.go b/clusterpolicies/v2/genhelper.go old mode 100755 new mode 100644 index c772345..1894fa5 --- a/clusterpolicies/v2/genhelper.go +++ b/clusterpolicies/v2/genhelper.go @@ -11,7 +11,6 @@ import ( "log/slog" "net/http" "net/url" - "strings" "github.com/databricks/sdk-go/auth" "github.com/databricks/sdk-go/core/apierr" @@ -177,46 +176,3 @@ func flattenQueryValue(params url.Values, key string, value any) { params.Add(key, fmt.Sprintf("%v", value)) } } - -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). -type pathBuilder struct { - path strings.Builder - raw strings.Builder -} - -// literal appends a static path segment, identical on the decoded and escaped -// paths. -func (b *pathBuilder) literal(s string) { - b.path.WriteString(s) - b.raw.WriteString(s) -} - -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. -func (b *pathBuilder) singleSegment(v any) { - s := fmt.Sprintf("%v", v) - b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) -} - -// multiSegments appends a multi-segment path parameter: the value spans several -// path segments, so each segment is escaped but the "/" separators are kept. -// The value is formatted with %v so strings, enums, and numbers all work. -func (b *pathBuilder) multiSegments(v any) { - s := fmt.Sprintf("%v", v) - b.path.WriteString(s) - segments := strings.Split(s, "/") - for i, seg := range segments { - segments[i] = url.PathEscape(seg) - } - b.raw.WriteString(strings.Join(segments, "/")) -} - -func (b *pathBuilder) build() (path, rawPath string) { - return b.path.String(), b.raw.String() -} diff --git a/clusterpolicies/v2/model.go b/clusterpolicies/v2/model.go old mode 100755 new mode 100644 index 1dcc3e5..334c233 --- a/clusterpolicies/v2/model.go +++ b/clusterpolicies/v2/model.go @@ -2,10 +2,6 @@ package clusterpolicies -import ( - "github.com/databricks/sdk-go/core/types" -) - type ListOrder string const ( @@ -24,22 +20,6 @@ const ( PolicySortColumn_PolicyName PolicySortColumn = "POLICY_NAME" ) -// Represents a cluster policy revision. -// -// Only the 100 most recent revisions are stored for each cluster policy.. -type ClusterPolicyRevision struct { - // ID of the cluster policy revision. - RevisionId *string - // Time when the cluster policy revision was created. - CreateTime *types.Time - // Settings used to create/edit the policy. - Settings *PolicyOwnAttributes - // Name of the user who edited this policy. - EditUser *string - // Whether this is the current revision. - IsCurrent *bool -} - type CreatePolicyRequest struct { // Cluster Policy name requested by the user. This has to be unique. Length must // be between 1 and 100 characters. @@ -128,13 +108,6 @@ type EditPolicyRequest struct { type EditPolicyResponse struct { } -// Request to get a cluster policy revision by ID.. -type GetClusterPolicyRevisionRequest struct { - // The fully qualified resource name of the cluster policy revision. Format: - // cluster-policies/{policy_id}/revisions/{revision_id}. - Name *string -} - type GetPolicyRequest struct { // Canonical unique identifier for the Cluster Policy. PolicyId *string @@ -222,25 +195,6 @@ type Library_Lib_Requirements struct { func (*Library_Lib_Requirements) isLibrary_Lib() {} -// Request to list cluster policy revisions.. -type ListClusterPolicyRevisionsRequest struct { - // The fully qualified resource name of the parent cluster. Format: - // cluster-policies/{policy_id}. - Parent *string - // Maximum number of cluster policy revisions to return per page. - PageSize *int - // Pagination token from a previous list cluster policy revisions request. - PageToken *string -} - -// Response when listing cluster policy revisions.. -type ListClusterPolicyRevisionsResponse struct { - // Cluster policy revisions in the current page. - ClusterPolicyRevisions []ClusterPolicyRevision - // Token for fetching the next page. Empty when there are no more results. - NextPageToken *string -} - type ListPoliciesRequest struct { // The order in which the policies get listed. * `DESC` - Sort result list in // descending order. * `ASC` - Sort result list in ascending order. @@ -318,41 +272,6 @@ type Policy struct { Libraries []Library } -type PolicyOwnAttributes struct { - // Cluster Policy name requested by the user. This has to be unique. Length must - // be between 1 and 100 characters. - Name *string - // Policy definition document expressed in [Databricks Cluster Policy Definition - // Language]. - // - // [Databricks Cluster Policy Definition Language]: https://docs.databricks.com/administration-guide/clusters/policy-definition.html - Definition *string - // Additional human-readable description of the cluster policy. - Description *string - // ID of the policy family. The cluster policy's policy definition inherits the - // policy family's policy definition. - // - // Cannot be used with `definition`. Use `policy_family_definition_overrides` - // instead to customize the policy definition. - PolicyFamilyId *string - // Policy definition JSON document expressed in [Databricks Policy Definition - // Language]. The JSON document must be passed as a string and cannot be - // embedded in the requests. - // - // You can use this to customize the policy definition inherited from the policy - // family. Policy rules specified here are merged into the inherited policy - // definition. - // - // [Databricks Policy Definition Language]: https://docs.databricks.com/administration-guide/clusters/policy-definition.html - PolicyFamilyDefinitionOverrides *string - // Max number of clusters per user that can be active using this policy. If not - // present, there is no max limit. - MaxClustersPerUser *int64 - // A list of libraries to be installed on the next cluster restart that uses - // this policy. The maximum number of libraries is 500. - Libraries []Library -} - type PythonPyPiLibrary struct { // The name of the pypi package to install. An optional exact version // specification is also supported. Examples: "simplejson" and @@ -370,10 +289,3 @@ type RCranLibrary struct { // CRAN repo is used. Repo *string } - -// Request to roll back cluster policy.. -type RollbackClusterPolicyRequest struct { - // The fully qualified resource name of the cluster policy revision. Format: - // cluster-policies/{policy_id}/revisions/{revision_id}. - Name *string -} diff --git a/clusterpolicies/v2/wire.go b/clusterpolicies/v2/wire.go old mode 100755 new mode 100644 index 78c332f..ee9835b --- a/clusterpolicies/v2/wire.go +++ b/clusterpolicies/v2/wire.go @@ -3,34 +3,53 @@ package clusterpolicies import ( + "bytes" + "encoding/json" "fmt" - - "github.com/databricks/sdk-go/core/types" + "strconv" ) -type clusterPolicyRevisionWire struct { - RevisionId *string `json:"revision_id,omitempty"` - CreateTime *types.Time `json:"create_time,omitempty"` - Settings *policyOwnAttributesWire `json:"settings,omitempty"` - EditUser *string `json:"edit_user,omitempty"` - IsCurrent *bool `json:"is_current,omitempty"` +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil } -func clusterPolicyRevisionFromWire(w *clusterPolicyRevisionWire) (*ClusterPolicyRevision, error) { - if w == nil { +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { return nil, nil } - settingsPublicValue, err := policyOwnAttributesFromWire(w.Settings) - if err != nil { - return nil, fmt.Errorf("%s: %w", "ClusterPolicyRevision.Settings", err) - } - return &ClusterPolicyRevision{ - RevisionId: w.RevisionId, - CreateTime: w.CreateTime, - Settings: settingsPublicValue, - EditUser: w.EditUser, - IsCurrent: w.IsCurrent, - }, nil + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil } type createPolicyRequestWire struct { @@ -39,7 +58,7 @@ type createPolicyRequestWire struct { Description *string `json:"description,omitempty"` PolicyFamilyId *string `json:"policy_family_id,omitempty"` PolicyFamilyDefinitionOverrides *string `json:"policy_family_definition_overrides,omitempty"` - MaxClustersPerUser *int64 `json:"max_clusters_per_user,omitempty"` + MaxClustersPerUser *wireInt64 `json:"max_clusters_per_user,omitempty"` Libraries []libraryWire `json:"libraries,omitempty"` } @@ -47,6 +66,10 @@ func createPolicyRequestToWire(v *CreatePolicyRequest) (*createPolicyRequestWire if v == nil { return nil, nil } + maxClustersPerUserWireValue, err := int64ToWire(v.MaxClustersPerUser) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreatePolicyRequest.MaxClustersPerUser", err) + } librariesWireValue, err := convertSlice(v.Libraries, libraryToWire) if err != nil { return nil, fmt.Errorf("%s: %w", "CreatePolicyRequest.Libraries", err) @@ -57,7 +80,7 @@ func createPolicyRequestToWire(v *CreatePolicyRequest) (*createPolicyRequestWire Description: v.Description, PolicyFamilyId: v.PolicyFamilyId, PolicyFamilyDefinitionOverrides: v.PolicyFamilyDefinitionOverrides, - MaxClustersPerUser: v.MaxClustersPerUser, + MaxClustersPerUser: maxClustersPerUserWireValue, Libraries: librariesWireValue, }, nil } @@ -95,7 +118,7 @@ type editPolicyRequestWire struct { Description *string `json:"description,omitempty"` PolicyFamilyId *string `json:"policy_family_id,omitempty"` PolicyFamilyDefinitionOverrides *string `json:"policy_family_definition_overrides,omitempty"` - MaxClustersPerUser *int64 `json:"max_clusters_per_user,omitempty"` + MaxClustersPerUser *wireInt64 `json:"max_clusters_per_user,omitempty"` Libraries []libraryWire `json:"libraries,omitempty"` } @@ -103,6 +126,10 @@ func editPolicyRequestToWire(v *EditPolicyRequest) (*editPolicyRequestWire, erro if v == nil { return nil, nil } + maxClustersPerUserWireValue, err := int64ToWire(v.MaxClustersPerUser) + if err != nil { + return nil, fmt.Errorf("%s: %w", "EditPolicyRequest.MaxClustersPerUser", err) + } librariesWireValue, err := convertSlice(v.Libraries, libraryToWire) if err != nil { return nil, fmt.Errorf("%s: %w", "EditPolicyRequest.Libraries", err) @@ -114,7 +141,7 @@ func editPolicyRequestToWire(v *EditPolicyRequest) (*editPolicyRequestWire, erro Description: v.Description, PolicyFamilyId: v.PolicyFamilyId, PolicyFamilyDefinitionOverrides: v.PolicyFamilyDefinitionOverrides, - MaxClustersPerUser: v.MaxClustersPerUser, + MaxClustersPerUser: maxClustersPerUserWireValue, Libraries: librariesWireValue, }, nil } @@ -272,42 +299,6 @@ func libraryFromWire(w *libraryWire) (*Library, error) { }, nil } -type listClusterPolicyRevisionsRequestWire struct { - Parent *string `json:"parent,omitempty"` - PageSize *int `json:"page_size,omitempty"` - PageToken *string `json:"page_token,omitempty"` -} - -func listClusterPolicyRevisionsRequestToWire(v *ListClusterPolicyRevisionsRequest) (*listClusterPolicyRevisionsRequestWire, error) { - if v == nil { - return nil, nil - } - return &listClusterPolicyRevisionsRequestWire{ - Parent: v.Parent, - PageSize: v.PageSize, - PageToken: v.PageToken, - }, nil -} - -type listClusterPolicyRevisionsResponseWire struct { - ClusterPolicyRevisions []clusterPolicyRevisionWire `json:"cluster_policy_revisions,omitempty"` - NextPageToken *string `json:"next_page_token,omitempty"` -} - -func listClusterPolicyRevisionsResponseFromWire(w *listClusterPolicyRevisionsResponseWire) (*ListClusterPolicyRevisionsResponse, error) { - if w == nil { - return nil, nil - } - clusterPolicyRevisionsPublicValue, err := convertSlice(w.ClusterPolicyRevisions, clusterPolicyRevisionFromWire) - if err != nil { - return nil, fmt.Errorf("%s: %w", "ListClusterPolicyRevisionsResponse.ClusterPolicyRevisions", err) - } - return &ListClusterPolicyRevisionsResponse{ - ClusterPolicyRevisions: clusterPolicyRevisionsPublicValue, - NextPageToken: w.NextPageToken, - }, nil -} - type listPoliciesRequestWire struct { SortOrder ListOrder `json:"sort_order,omitempty"` SortColumn PolicySortColumn `json:"sort_column,omitempty"` @@ -371,14 +362,14 @@ func mavenLibraryFromWire(w *mavenLibraryWire) (*MavenLibrary, error) { type policyWire struct { PolicyId *string `json:"policy_id,omitempty"` CreatorUserName *string `json:"creator_user_name,omitempty"` - CreatedAtTimestamp *int64 `json:"created_at_timestamp,omitempty"` + CreatedAtTimestamp *wireInt64 `json:"created_at_timestamp,omitempty"` IsDefault *bool `json:"is_default,omitempty"` Name *string `json:"name,omitempty"` Definition *string `json:"definition,omitempty"` Description *string `json:"description,omitempty"` PolicyFamilyId *string `json:"policy_family_id,omitempty"` PolicyFamilyDefinitionOverrides *string `json:"policy_family_definition_overrides,omitempty"` - MaxClustersPerUser *int64 `json:"max_clusters_per_user,omitempty"` + MaxClustersPerUser *wireInt64 `json:"max_clusters_per_user,omitempty"` Libraries []libraryWire `json:"libraries,omitempty"` } @@ -386,6 +377,14 @@ func policyFromWire(w *policyWire) (*Policy, error) { if w == nil { return nil, nil } + createdAtTimestampPublicValue, err := int64FromWire(w.CreatedAtTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Policy.CreatedAtTimestamp", err) + } + maxClustersPerUserPublicValue, err := int64FromWire(w.MaxClustersPerUser) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Policy.MaxClustersPerUser", err) + } librariesPublicValue, err := convertSlice(w.Libraries, libraryFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "Policy.Libraries", err) @@ -393,43 +392,14 @@ func policyFromWire(w *policyWire) (*Policy, error) { return &Policy{ PolicyId: w.PolicyId, CreatorUserName: w.CreatorUserName, - CreatedAtTimestamp: w.CreatedAtTimestamp, + CreatedAtTimestamp: createdAtTimestampPublicValue, IsDefault: w.IsDefault, Name: w.Name, Definition: w.Definition, Description: w.Description, PolicyFamilyId: w.PolicyFamilyId, PolicyFamilyDefinitionOverrides: w.PolicyFamilyDefinitionOverrides, - MaxClustersPerUser: w.MaxClustersPerUser, - Libraries: librariesPublicValue, - }, nil -} - -type policyOwnAttributesWire struct { - Name *string `json:"name,omitempty"` - Definition *string `json:"definition,omitempty"` - Description *string `json:"description,omitempty"` - PolicyFamilyId *string `json:"policy_family_id,omitempty"` - PolicyFamilyDefinitionOverrides *string `json:"policy_family_definition_overrides,omitempty"` - MaxClustersPerUser *int64 `json:"max_clusters_per_user,omitempty"` - Libraries []libraryWire `json:"libraries,omitempty"` -} - -func policyOwnAttributesFromWire(w *policyOwnAttributesWire) (*PolicyOwnAttributes, error) { - if w == nil { - return nil, nil - } - librariesPublicValue, err := convertSlice(w.Libraries, libraryFromWire) - if err != nil { - return nil, fmt.Errorf("%s: %w", "PolicyOwnAttributes.Libraries", err) - } - return &PolicyOwnAttributes{ - Name: w.Name, - Definition: w.Definition, - Description: w.Description, - PolicyFamilyId: w.PolicyFamilyId, - PolicyFamilyDefinitionOverrides: w.PolicyFamilyDefinitionOverrides, - MaxClustersPerUser: w.MaxClustersPerUser, + MaxClustersPerUser: maxClustersPerUserPublicValue, Libraries: librariesPublicValue, }, nil } @@ -484,19 +454,6 @@ func rCranLibraryFromWire(w *rCranLibraryWire) (*RCranLibrary, error) { }, nil } -type rollbackClusterPolicyRequestWire struct { - Name *string `json:"name,omitempty"` -} - -func rollbackClusterPolicyRequestToWire(v *RollbackClusterPolicyRequest) (*rollbackClusterPolicyRequestWire, error) { - if v == nil { - return nil, nil - } - return &rollbackClusterPolicyRequestWire{ - Name: v.Name, - }, nil -} - func convertSlice[T, W any](s []T, conv func(*T) (*W, error)) ([]W, error) { if s == nil { return nil, nil diff --git a/clusters/CHANGELOG.md b/clusters/CHANGELOG.md index 6224c04..19f237c 100644 --- a/clusters/CHANGELOG.md +++ b/clusters/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/clusters/go.mod b/clusters/go.mod index 5cc50b5..d552363 100644 --- a/clusters/go.mod +++ b/clusters/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/clusters/internal/version.go b/clusters/internal/version.go index 97c9836..1fd0486 100644 --- a/clusters/internal/version.go +++ b/clusters/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-clusters" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/clusters/v2/client.go b/clusters/v2/client.go old mode 100755 new mode 100644 index 880a16f..5428714 --- a/clusters/v2/client.go +++ b/clusters/v2/client.go @@ -79,8 +79,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Retrieves a list of events about the activity of a cluster. This API is // paginated. If there are more events to read, the response includes all the // parameters necessary to request the next page of events. -func (c *internalClient) ListEvents(ctx context.Context, req *ListEventsRequest, opts ...call.Option) (*GetEventsResponse, error) { - wireReq, err := listEventsRequestToWire(req) +func (c *internalClient) ListEvents(ctx context.Context, req ListEventsRequest, opts ...call.Option) (*GetEventsResponse, error) { + wireReq, err := listEventsRequestToWire(&req) if err != nil { return nil, err } @@ -149,7 +149,7 @@ func (c *internalClient) ListEvents(ctx context.Context, req *ListEventsRequest, // // For example: // -// for item, err := range c.ListEventsIter(ctx, &ListEventsRequest{}) { +// for item, err := range c.ListEventsIter(ctx, ListEventsRequest{}) { // if err != nil { // return err // } @@ -161,16 +161,13 @@ func (c *internalClient) ListEvents(ctx context.Context, req *ListEventsRequest, // // Callers who need custom pagination logic should use // ListEvents directly. -func (c *internalClient) ListEventsIter(ctx context.Context, req *ListEventsRequest, opts ...call.Option) iter.Seq2[*ClusterEvent, error] { +func (c *internalClient) ListEventsIter(ctx context.Context, req ListEventsRequest, opts ...call.Option) iter.Seq2[*ClusterEvent, error] { return func(yield func(*ClusterEvent, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListEventsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListEvents(ctx, &pageReq, opts...) + resp, err := c.ListEvents(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -188,265 +185,11 @@ func (c *internalClient) ListEventsIter(ctx context.Context, req *ListEventsRequ } } -// Get details of a cluster revision. -func (c *internalClient) GetClusterRevision(ctx context.Context, req *GetClusterRevisionRequest, opts ...call.Option) (*ClusterRevision, error) { - - headers := http.Header{} - headers.Set("Content-Type", "application/json") - if c.workspaceID != "" { - headers.Set("X-Databricks-Workspace-Id", c.workspaceID) - } - - baseURL, err := url.Parse(c.host) - if err != nil { - return nil, err - } - pb := pathBuilder{} - pb.literal("/api/2.1/") - pb.singleSegment(*req.Name) - baseURL.Path, baseURL.RawPath = pb.build() - queryParams := url.Values{} - baseURL.RawQuery = queryParams.Encode() - urlStr := baseURL.String() - - var resp *ClusterRevision - - call := func(ctx context.Context) error { - httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ - Method: "GET", - URL: urlStr, - Credentials: c.credentials, - UserAgent: c.userAgent, - Headers: headers, - }) - if err != nil { - return err - } - - respBody, _, err := executeHTTPCall(httpCallOptions{ - req: httpReq, - client: c.httpClient, - logger: c.logger, - }) - if err != nil { - return err - } - var wireResp clusterRevisionWire - if err := json.Unmarshal(respBody, &wireResp); err != nil { - return err - } - resp, err = clusterRevisionFromWire(&wireResp) - if err != nil { - return err - } - return nil - } - - if err := executeCall(ctx, call, opts); err != nil { - return nil, err - } - return resp, nil -} - -// Lists a cluster's revisions, ordered from most to least recent. -func (c *internalClient) ListClusterRevisions(ctx context.Context, req *ListClusterRevisionsRequest, opts ...call.Option) (*ListClusterRevisionsResponse, error) { - wireReq, err := listClusterRevisionsRequestToWire(req) - if err != nil { - return nil, err - } - - headers := http.Header{} - headers.Set("Content-Type", "application/json") - if c.workspaceID != "" { - headers.Set("X-Databricks-Workspace-Id", c.workspaceID) - } - - baseURL, err := url.Parse(c.host) - if err != nil { - return nil, err - } - pb := pathBuilder{} - pb.literal("/api/2.1/") - pb.singleSegment(*req.Parent) - pb.literal("/revisions") - baseURL.Path, baseURL.RawPath = pb.build() - queryParams := url.Values{} - if err := addQueryValue(queryParams, "page_size", wireReq.PageSize); err != nil { - return nil, err - } - if err := addQueryValue(queryParams, "page_token", wireReq.PageToken); err != nil { - return nil, err - } - baseURL.RawQuery = queryParams.Encode() - urlStr := baseURL.String() - - var resp *ListClusterRevisionsResponse - - call := func(ctx context.Context) error { - httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ - Method: "GET", - URL: urlStr, - Credentials: c.credentials, - UserAgent: c.userAgent, - Headers: headers, - }) - if err != nil { - return err - } - - respBody, _, err := executeHTTPCall(httpCallOptions{ - req: httpReq, - client: c.httpClient, - logger: c.logger, - }) - if err != nil { - return err - } - var wireResp listClusterRevisionsResponseWire - if err := json.Unmarshal(respBody, &wireResp); err != nil { - return err - } - resp, err = listClusterRevisionsResponseFromWire(&wireResp) - if err != nil { - return err - } - return nil - } - - if err := executeCall(ctx, call, opts); err != nil { - return nil, err - } - return resp, nil -} - -// ListClusterRevisionsIter returns an iterator that iterates -// over the results of ListClusterRevisions. -// -// For example: -// -// for item, err := range c.ListClusterRevisionsIter(ctx, &ListClusterRevisionsRequest{}) { -// if err != nil { -// return err -// } -// fmt.Println(item) -// } -// -// Options opts are passed to each ListClusterRevisions call -// made by the iterator under the hood. -// -// Callers who need custom pagination logic should use -// ListClusterRevisions directly. -func (c *internalClient) ListClusterRevisionsIter(ctx context.Context, req *ListClusterRevisionsRequest, opts ...call.Option) iter.Seq2[*ClusterRevision, error] { - return func(yield func(*ClusterRevision, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListClusterRevisionsRequest{} - if req != nil { - pageReq = *req - } - for { - resp, err := c.ListClusterRevisions(ctx, &pageReq, opts...) - if err != nil { - yield(nil, err) - return - } - for i := range resp.ClusterRevisions { - if !yield(&resp.ClusterRevisions[i], nil) { - return - } - } - if resp.NextPageToken == nil || *resp.NextPageToken == "" { - return - } - pageReq.PageToken = resp.NextPageToken - } - } -} - -// Rolls back a cluster to a previous revision. A cluster can be rolled back if -// it is in a `RUNNING` or `TERMINATED` state. -// -// If a cluster is rolled back while in a `RUNNING` state, it will be restarted -// so that the new attributes can take effect. -// -// If a cluster is rolled back while in a `TERMINATED` state, it will remain -// `TERMINATED`. The next time it is started using the `clusters/start` API, the -// new attributes will take effect. Any attempt to roll back a cluster in any -// other state will be rejected with an `INVALID_PARAMETER_VALUE` error code. -func (c *internalClient) RollbackCluster(ctx context.Context, req *RollbackClusterRequest, opts ...call.Option) (*ClusterRevision, error) { - wireReq, err := rollbackClusterRequestToWire(req) - if err != nil { - return nil, err - } - body, err := json.Marshal(wireReq) - if err != nil { - return nil, err - } - - headers := http.Header{} - headers.Set("Content-Type", "application/json") - if c.workspaceID != "" { - headers.Set("X-Databricks-Workspace-Id", c.workspaceID) - } - - baseURL, err := url.Parse(c.host) - if err != nil { - return nil, err - } - pb := pathBuilder{} - pb.literal("/api/2.1/") - pb.singleSegment(*req.Name) - pb.literal("/rollback") - baseURL.Path, baseURL.RawPath = pb.build() - queryParams := url.Values{} - baseURL.RawQuery = queryParams.Encode() - urlStr := baseURL.String() - - var resp *ClusterRevision - - call := func(ctx context.Context) error { - httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ - Method: "POST", - URL: urlStr, - Credentials: c.credentials, - UserAgent: c.userAgent, - Headers: headers, - Body: bytes.NewBuffer(body), - }) - if err != nil { - return err - } - - respBody, _, err := executeHTTPCall(httpCallOptions{ - req: httpReq, - client: c.httpClient, - logger: c.logger, - }) - if err != nil { - return err - } - var wireResp clusterRevisionWire - if err := json.Unmarshal(respBody, &wireResp); err != nil { - return err - } - resp, err = clusterRevisionFromWire(&wireResp) - if err != nil { - return err - } - return nil - } - - if err := executeCall(ctx, call, opts); err != nil { - return nil, err - } - return resp, nil -} - // Change the owner of the cluster. You must be an admin and the cluster must be // terminated to perform this operation. The service principal application ID // can be supplied as an argument to `owner_username`. -func (c *internalClient) ChangeClusterOwner(ctx context.Context, req *ChangeClusterOwnerRequest, opts ...call.Option) (*ChangeClusterOwnerResponse, error) { - wireReq, err := changeClusterOwnerRequestToWire(req) +func (c *internalClient) ChangeClusterOwner(ctx context.Context, req ChangeClusterOwnerRequest, opts ...call.Option) (*ChangeClusterOwnerResponse, error) { + wireReq, err := changeClusterOwnerRequestToWire(&req) if err != nil { return nil, err } @@ -519,8 +262,8 @@ func (c *internalClient) ChangeClusterOwner(ctx context.Context, req *ChangeClus // Rather than authoring the cluster's JSON definition from scratch, Databricks // recommends filling out the [create compute UI](/compute/configure.html) and // then copying the generated JSON definition from the UI. -func (c *internalClient) createClusterBase(ctx context.Context, req *CreateClusterRequest, opts ...call.Option) (*CreateClusterResponse, error) { - wireReq, err := createClusterRequestToWire(req) +func (c *internalClient) createClusterBase(ctx context.Context, req CreateClusterRequest, opts ...call.Option) (*CreateClusterResponse, error) { + wireReq, err := createClusterRequestToWire(&req) if err != nil { return nil, err } @@ -599,7 +342,7 @@ func (c *internalClient) createClusterBase(ctx context.Context, req *CreateClust // Rather than authoring the cluster's JSON definition from scratch, Databricks // recommends filling out the [create compute UI](/compute/configure.html) and // then copying the generated JSON definition from the UI. -func (c *internalClient) CreateCluster(ctx context.Context, req *CreateClusterRequest, opts ...call.Option) (*CreateClusterWaiter, error) { +func (c *internalClient) CreateCluster(ctx context.Context, req CreateClusterRequest, opts ...call.Option) (*CreateClusterWaiter, error) { resp, err := c.createClusterBase(ctx, req, opts...) if err != nil { return nil, err @@ -615,13 +358,18 @@ func (c *internalClient) CreateCluster(ctx context.Context, req *CreateClusterRe // CreateClusterWaiter tracks the state of the operation started by CreateCluster. type CreateClusterWaiter struct { - poll func(context.Context, *GetClusterRequest, ...call.Option) (*ClusterInfo, error) + poll func(context.Context, GetClusterRequest, ...call.Option) (*ClusterInfo, error) clusterId string } +// GetClusterId returns the ClusterId value used to identify the operation. +func (w *CreateClusterWaiter) GetClusterId() string { + return w.clusterId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *CreateClusterWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetClusterRequest{ + pollResp, err := w.poll(ctx, GetClusterRequest{ ClusterId: &w.clusterId, }, opts...) if err != nil { @@ -646,7 +394,7 @@ func (w *CreateClusterWaiter) Done(ctx context.Context, opts ...call.Option) (bo func (w *CreateClusterWaiter) Wait(ctx context.Context, opts ...lro.Option) (*ClusterInfo, error) { var result *ClusterInfo poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetClusterRequest{ + pollResp, err := w.poll(ctx, GetClusterRequest{ ClusterId: &w.clusterId, }) if err != nil { @@ -683,8 +431,8 @@ func (w *CreateClusterWaiter) Wait(ctx context.Context, opts ...lro.Option) (*Cl // asynchronously. Once the termination has completed, the cluster will be in a // `TERMINATED` state. If the cluster is already in a `TERMINATING` or // `TERMINATED` state, nothing will happen. -func (c *internalClient) deleteClusterBase(ctx context.Context, req *DeleteClusterRequest, opts ...call.Option) (*DeleteClusterResponse, error) { - wireReq, err := deleteClusterRequestToWire(req) +func (c *internalClient) deleteClusterBase(ctx context.Context, req DeleteClusterRequest, opts ...call.Option) (*DeleteClusterResponse, error) { + wireReq, err := deleteClusterRequestToWire(&req) if err != nil { return nil, err } @@ -746,7 +494,7 @@ func (c *internalClient) deleteClusterBase(ctx context.Context, req *DeleteClust // asynchronously. Once the termination has completed, the cluster will be in a // `TERMINATED` state. If the cluster is already in a `TERMINATING` or // `TERMINATED` state, nothing will happen. -func (c *internalClient) DeleteCluster(ctx context.Context, req *DeleteClusterRequest, opts ...call.Option) (*DeleteClusterWaiter, error) { +func (c *internalClient) DeleteCluster(ctx context.Context, req DeleteClusterRequest, opts ...call.Option) (*DeleteClusterWaiter, error) { if req.ClusterId == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "ClusterId") } @@ -763,13 +511,18 @@ func (c *internalClient) DeleteCluster(ctx context.Context, req *DeleteClusterRe // DeleteClusterWaiter tracks the state of the operation started by DeleteCluster. type DeleteClusterWaiter struct { - poll func(context.Context, *GetClusterRequest, ...call.Option) (*ClusterInfo, error) + poll func(context.Context, GetClusterRequest, ...call.Option) (*ClusterInfo, error) clusterId string } +// GetClusterId returns the ClusterId value used to identify the operation. +func (w *DeleteClusterWaiter) GetClusterId() string { + return w.clusterId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *DeleteClusterWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetClusterRequest{ + pollResp, err := w.poll(ctx, GetClusterRequest{ ClusterId: &w.clusterId, }, opts...) if err != nil { @@ -794,7 +547,7 @@ func (w *DeleteClusterWaiter) Done(ctx context.Context, opts ...call.Option) (bo func (w *DeleteClusterWaiter) Wait(ctx context.Context, opts ...lro.Option) (*ClusterInfo, error) { var result *ClusterInfo poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetClusterRequest{ + pollResp, err := w.poll(ctx, GetClusterRequest{ ClusterId: &w.clusterId, }) if err != nil { @@ -839,8 +592,8 @@ func (w *DeleteClusterWaiter) Wait(ctx context.Context, opts ...lro.Option) (*Cl // state will be rejected with an `INVALID_STATE` error code. // // Clusters created by the Databricks Jobs service cannot be edited. -func (c *internalClient) editClusterBase(ctx context.Context, req *EditClusterRequest, opts ...call.Option) (*EditClusterResponse, error) { - wireReq, err := editClusterRequestToWire(req) +func (c *internalClient) editClusterBase(ctx context.Context, req EditClusterRequest, opts ...call.Option) (*EditClusterResponse, error) { + wireReq, err := editClusterRequestToWire(&req) if err != nil { return nil, err } @@ -910,7 +663,7 @@ func (c *internalClient) editClusterBase(ctx context.Context, req *EditClusterRe // state will be rejected with an `INVALID_STATE` error code. // // Clusters created by the Databricks Jobs service cannot be edited. -func (c *internalClient) EditCluster(ctx context.Context, req *EditClusterRequest, opts ...call.Option) (*EditClusterWaiter, error) { +func (c *internalClient) EditCluster(ctx context.Context, req EditClusterRequest, opts ...call.Option) (*EditClusterWaiter, error) { if req.ClusterId == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "ClusterId") } @@ -927,13 +680,18 @@ func (c *internalClient) EditCluster(ctx context.Context, req *EditClusterReques // EditClusterWaiter tracks the state of the operation started by EditCluster. type EditClusterWaiter struct { - poll func(context.Context, *GetClusterRequest, ...call.Option) (*ClusterInfo, error) + poll func(context.Context, GetClusterRequest, ...call.Option) (*ClusterInfo, error) clusterId string } +// GetClusterId returns the ClusterId value used to identify the operation. +func (w *EditClusterWaiter) GetClusterId() string { + return w.clusterId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *EditClusterWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetClusterRequest{ + pollResp, err := w.poll(ctx, GetClusterRequest{ ClusterId: &w.clusterId, }, opts...) if err != nil { @@ -958,7 +716,7 @@ func (w *EditClusterWaiter) Done(ctx context.Context, opts ...call.Option) (bool func (w *EditClusterWaiter) Wait(ctx context.Context, opts ...lro.Option) (*ClusterInfo, error) { var result *ClusterInfo poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetClusterRequest{ + pollResp, err := w.poll(ctx, GetClusterRequest{ ClusterId: &w.clusterId, }) if err != nil { @@ -993,8 +751,8 @@ func (w *EditClusterWaiter) Wait(ctx context.Context, opts ...lro.Option) (*Clus // Retrieves the information for a cluster given its identifier. Clusters can be // described while they are running, or up to 60 days after they are terminated. -func (c *internalClient) GetCluster(ctx context.Context, req *GetClusterRequest, opts ...call.Option) (*ClusterInfo, error) { - wireReq, err := getClusterRequestToWire(req) +func (c *internalClient) GetCluster(ctx context.Context, req GetClusterRequest, opts ...call.Option) (*ClusterInfo, error) { + wireReq, err := getClusterRequestToWire(&req) if err != nil { return nil, err } @@ -1058,7 +816,7 @@ func (c *internalClient) GetCluster(ctx context.Context, req *GetClusterRequest, // Returns a list of availability zones where clusters can be created in (For // example, us-west-2a). These zones can be used to launch a cluster. -func (c *internalClient) ListAvailableZones(ctx context.Context, req *ListAvailableZonesRequest, opts ...call.Option) (*ListAvailableZonesResponse, error) { +func (c *internalClient) ListAvailableZones(ctx context.Context, req ListAvailableZonesRequest, opts ...call.Option) (*ListAvailableZonesResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1117,8 +875,8 @@ func (c *internalClient) ListAvailableZones(ctx context.Context, req *ListAvaila // Return information about all pinned and active clusters, and all clusters // terminated within the last 30 days. Clusters terminated prior to this period // are not included. -func (c *internalClient) ListClusters(ctx context.Context, req *ListClustersRequest, opts ...call.Option) (*ListClustersResponse, error) { - wireReq, err := listClustersRequestToWire(req) +func (c *internalClient) ListClusters(ctx context.Context, req ListClustersRequest, opts ...call.Option) (*ListClustersResponse, error) { + wireReq, err := listClustersRequestToWire(&req) if err != nil { return nil, err } @@ -1188,7 +946,7 @@ func (c *internalClient) ListClusters(ctx context.Context, req *ListClustersRequ // // For example: // -// for item, err := range c.ListClustersIter(ctx, &ListClustersRequest{}) { +// for item, err := range c.ListClustersIter(ctx, ListClustersRequest{}) { // if err != nil { // return err // } @@ -1200,16 +958,13 @@ func (c *internalClient) ListClusters(ctx context.Context, req *ListClustersRequ // // Callers who need custom pagination logic should use // ListClusters directly. -func (c *internalClient) ListClustersIter(ctx context.Context, req *ListClustersRequest, opts ...call.Option) iter.Seq2[*ClusterInfo, error] { +func (c *internalClient) ListClustersIter(ctx context.Context, req ListClustersRequest, opts ...call.Option) iter.Seq2[*ClusterInfo, error] { return func(yield func(*ClusterInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListClustersRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListClusters(ctx, &pageReq, opts...) + resp, err := c.ListClusters(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1229,7 +984,7 @@ func (c *internalClient) ListClustersIter(ctx context.Context, req *ListClusters // Returns a list of supported Spark node types. These node types can be used to // launch a cluster. -func (c *internalClient) ListNodeTypes(ctx context.Context, req *ListNodeTypesRequest, opts ...call.Option) (*ListNodeTypesResponse, error) { +func (c *internalClient) ListNodeTypes(ctx context.Context, req ListNodeTypesRequest, opts ...call.Option) (*ListNodeTypesResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1287,7 +1042,7 @@ func (c *internalClient) ListNodeTypes(ctx context.Context, req *ListNodeTypesRe // Returns the list of available Spark versions. These versions can be used to // launch a cluster. -func (c *internalClient) ListSparkVersions(ctx context.Context, req *GetSparkVersionsRequest, opts ...call.Option) (*GetSparkVersionsResponse, error) { +func (c *internalClient) ListSparkVersions(ctx context.Context, req GetSparkVersionsRequest, opts ...call.Option) (*GetSparkVersionsResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1349,8 +1104,8 @@ func (c *internalClient) ListSparkVersions(ctx context.Context, req *GetSparkVer // In addition, users will no longer see permanently deleted clusters in the // cluster list, and API users can no longer perform any action on permanently // deleted clusters. -func (c *internalClient) PermanentDeleteCluster(ctx context.Context, req *PermanentDeleteClusterRequest, opts ...call.Option) (*PermanentDeleteClusterResponse, error) { - wireReq, err := permanentDeleteClusterRequestToWire(req) +func (c *internalClient) PermanentDeleteCluster(ctx context.Context, req PermanentDeleteClusterRequest, opts ...call.Option) (*PermanentDeleteClusterResponse, error) { + wireReq, err := permanentDeleteClusterRequestToWire(&req) if err != nil { return nil, err } @@ -1411,8 +1166,8 @@ func (c *internalClient) PermanentDeleteCluster(ctx context.Context, req *Perman // Pinning a cluster ensures that the cluster will always be returned by the // ListClusters API. Pinning a cluster that is already pinned will have no // effect. This API can only be called by workspace admins. -func (c *internalClient) PinCluster(ctx context.Context, req *PinClusterRequest, opts ...call.Option) (*PinClusterResponse, error) { - wireReq, err := pinClusterRequestToWire(req) +func (c *internalClient) PinCluster(ctx context.Context, req PinClusterRequest, opts ...call.Option) (*PinClusterResponse, error) { + wireReq, err := pinClusterRequestToWire(&req) if err != nil { return nil, err } @@ -1472,8 +1227,8 @@ func (c *internalClient) PinCluster(ctx context.Context, req *PinClusterRequest, // Resizes a cluster to have a desired number of workers. This will fail unless // the cluster is in a `RUNNING` state. -func (c *internalClient) resizeClusterBase(ctx context.Context, req *ResizeClusterRequest, opts ...call.Option) (*ResizeClusterResponse, error) { - wireReq, err := resizeClusterRequestToWire(req) +func (c *internalClient) resizeClusterBase(ctx context.Context, req ResizeClusterRequest, opts ...call.Option) (*ResizeClusterResponse, error) { + wireReq, err := resizeClusterRequestToWire(&req) if err != nil { return nil, err } @@ -1533,7 +1288,7 @@ func (c *internalClient) resizeClusterBase(ctx context.Context, req *ResizeClust // Resizes a cluster to have a desired number of workers. This will fail unless // the cluster is in a `RUNNING` state. -func (c *internalClient) ResizeCluster(ctx context.Context, req *ResizeClusterRequest, opts ...call.Option) (*ResizeClusterWaiter, error) { +func (c *internalClient) ResizeCluster(ctx context.Context, req ResizeClusterRequest, opts ...call.Option) (*ResizeClusterWaiter, error) { if req.ClusterId == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "ClusterId") } @@ -1550,13 +1305,18 @@ func (c *internalClient) ResizeCluster(ctx context.Context, req *ResizeClusterRe // ResizeClusterWaiter tracks the state of the operation started by ResizeCluster. type ResizeClusterWaiter struct { - poll func(context.Context, *GetClusterRequest, ...call.Option) (*ClusterInfo, error) + poll func(context.Context, GetClusterRequest, ...call.Option) (*ClusterInfo, error) clusterId string } +// GetClusterId returns the ClusterId value used to identify the operation. +func (w *ResizeClusterWaiter) GetClusterId() string { + return w.clusterId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *ResizeClusterWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetClusterRequest{ + pollResp, err := w.poll(ctx, GetClusterRequest{ ClusterId: &w.clusterId, }, opts...) if err != nil { @@ -1581,7 +1341,7 @@ func (w *ResizeClusterWaiter) Done(ctx context.Context, opts ...call.Option) (bo func (w *ResizeClusterWaiter) Wait(ctx context.Context, opts ...lro.Option) (*ClusterInfo, error) { var result *ClusterInfo poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetClusterRequest{ + pollResp, err := w.poll(ctx, GetClusterRequest{ ClusterId: &w.clusterId, }) if err != nil { @@ -1616,8 +1376,8 @@ func (w *ResizeClusterWaiter) Wait(ctx context.Context, opts ...lro.Option) (*Cl // Restarts a Spark cluster with the supplied ID. If the cluster is not // currently in a `RUNNING` state, nothing will happen. -func (c *internalClient) restartClusterBase(ctx context.Context, req *RestartClusterRequest, opts ...call.Option) (*RestartClusterResponse, error) { - wireReq, err := restartClusterRequestToWire(req) +func (c *internalClient) restartClusterBase(ctx context.Context, req RestartClusterRequest, opts ...call.Option) (*RestartClusterResponse, error) { + wireReq, err := restartClusterRequestToWire(&req) if err != nil { return nil, err } @@ -1677,7 +1437,7 @@ func (c *internalClient) restartClusterBase(ctx context.Context, req *RestartClu // Restarts a Spark cluster with the supplied ID. If the cluster is not // currently in a `RUNNING` state, nothing will happen. -func (c *internalClient) RestartCluster(ctx context.Context, req *RestartClusterRequest, opts ...call.Option) (*RestartClusterWaiter, error) { +func (c *internalClient) RestartCluster(ctx context.Context, req RestartClusterRequest, opts ...call.Option) (*RestartClusterWaiter, error) { if req.ClusterId == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "ClusterId") } @@ -1694,13 +1454,18 @@ func (c *internalClient) RestartCluster(ctx context.Context, req *RestartCluster // RestartClusterWaiter tracks the state of the operation started by RestartCluster. type RestartClusterWaiter struct { - poll func(context.Context, *GetClusterRequest, ...call.Option) (*ClusterInfo, error) + poll func(context.Context, GetClusterRequest, ...call.Option) (*ClusterInfo, error) clusterId string } +// GetClusterId returns the ClusterId value used to identify the operation. +func (w *RestartClusterWaiter) GetClusterId() string { + return w.clusterId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *RestartClusterWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetClusterRequest{ + pollResp, err := w.poll(ctx, GetClusterRequest{ ClusterId: &w.clusterId, }, opts...) if err != nil { @@ -1725,7 +1490,7 @@ func (w *RestartClusterWaiter) Done(ctx context.Context, opts ...call.Option) (b func (w *RestartClusterWaiter) Wait(ctx context.Context, opts ...lro.Option) (*ClusterInfo, error) { var result *ClusterInfo poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetClusterRequest{ + pollResp, err := w.poll(ctx, GetClusterRequest{ ClusterId: &w.clusterId, }) if err != nil { @@ -1765,8 +1530,8 @@ func (w *RestartClusterWaiter) Wait(ctx context.Context, opts ...lro.Option) (*C // with the minimum number of nodes. - If the cluster is not currently in a // “TERMINATED“ state, nothing will happen. - Clusters launched to run a job // cannot be started. -func (c *internalClient) startClusterBase(ctx context.Context, req *StartClusterRequest, opts ...call.Option) (*StartClusterResponse, error) { - wireReq, err := startClusterRequestToWire(req) +func (c *internalClient) startClusterBase(ctx context.Context, req StartClusterRequest, opts ...call.Option) (*StartClusterResponse, error) { + wireReq, err := startClusterRequestToWire(&req) if err != nil { return nil, err } @@ -1831,7 +1596,7 @@ func (c *internalClient) startClusterBase(ctx context.Context, req *StartCluster // with the minimum number of nodes. - If the cluster is not currently in a // “TERMINATED“ state, nothing will happen. - Clusters launched to run a job // cannot be started. -func (c *internalClient) StartCluster(ctx context.Context, req *StartClusterRequest, opts ...call.Option) (*StartClusterWaiter, error) { +func (c *internalClient) StartCluster(ctx context.Context, req StartClusterRequest, opts ...call.Option) (*StartClusterWaiter, error) { if req.ClusterId == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "ClusterId") } @@ -1848,13 +1613,18 @@ func (c *internalClient) StartCluster(ctx context.Context, req *StartClusterRequ // StartClusterWaiter tracks the state of the operation started by StartCluster. type StartClusterWaiter struct { - poll func(context.Context, *GetClusterRequest, ...call.Option) (*ClusterInfo, error) + poll func(context.Context, GetClusterRequest, ...call.Option) (*ClusterInfo, error) clusterId string } +// GetClusterId returns the ClusterId value used to identify the operation. +func (w *StartClusterWaiter) GetClusterId() string { + return w.clusterId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *StartClusterWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetClusterRequest{ + pollResp, err := w.poll(ctx, GetClusterRequest{ ClusterId: &w.clusterId, }, opts...) if err != nil { @@ -1879,7 +1649,7 @@ func (w *StartClusterWaiter) Done(ctx context.Context, opts ...call.Option) (boo func (w *StartClusterWaiter) Wait(ctx context.Context, opts ...lro.Option) (*ClusterInfo, error) { var result *ClusterInfo poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetClusterRequest{ + pollResp, err := w.poll(ctx, GetClusterRequest{ ClusterId: &w.clusterId, }) if err != nil { @@ -1915,8 +1685,8 @@ func (w *StartClusterWaiter) Wait(ctx context.Context, opts ...lro.Option) (*Clu // Unpinning a cluster will allow the cluster to eventually be removed from the // ListClusters API. Unpinning a cluster that is not pinned will have no effect. // This API can only be called by workspace admins. -func (c *internalClient) UnpinCluster(ctx context.Context, req *UnpinClusterRequest, opts ...call.Option) (*UnpinClusterResponse, error) { - wireReq, err := unpinClusterRequestToWire(req) +func (c *internalClient) UnpinCluster(ctx context.Context, req UnpinClusterRequest, opts ...call.Option) (*UnpinClusterResponse, error) { + wireReq, err := unpinClusterRequestToWire(&req) if err != nil { return nil, err } @@ -1984,8 +1754,8 @@ func (c *internalClient) UnpinCluster(ctx context.Context, req *UnpinClusterRequ // using the `clusters/start` API. Attempts to update a cluster in any other // state will be rejected with an `INVALID_STATE` error code. Clusters created // by the Databricks Jobs service cannot be updated. -func (c *internalClient) updateClusterBase(ctx context.Context, req *UpdateClusterRequest, opts ...call.Option) (*UpdateClusterResponse, error) { - wireReq, err := updateClusterRequestToWire(req) +func (c *internalClient) updateClusterBase(ctx context.Context, req UpdateClusterRequest, opts ...call.Option) (*UpdateClusterResponse, error) { + wireReq, err := updateClusterRequestToWire(&req) if err != nil { return nil, err } @@ -2053,7 +1823,7 @@ func (c *internalClient) updateClusterBase(ctx context.Context, req *UpdateClust // using the `clusters/start` API. Attempts to update a cluster in any other // state will be rejected with an `INVALID_STATE` error code. Clusters created // by the Databricks Jobs service cannot be updated. -func (c *internalClient) UpdateCluster(ctx context.Context, req *UpdateClusterRequest, opts ...call.Option) (*UpdateClusterWaiter, error) { +func (c *internalClient) UpdateCluster(ctx context.Context, req UpdateClusterRequest, opts ...call.Option) (*UpdateClusterWaiter, error) { if req.ClusterId == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "ClusterId") } @@ -2070,13 +1840,18 @@ func (c *internalClient) UpdateCluster(ctx context.Context, req *UpdateClusterRe // UpdateClusterWaiter tracks the state of the operation started by UpdateCluster. type UpdateClusterWaiter struct { - poll func(context.Context, *GetClusterRequest, ...call.Option) (*ClusterInfo, error) + poll func(context.Context, GetClusterRequest, ...call.Option) (*ClusterInfo, error) clusterId string } +// GetClusterId returns the ClusterId value used to identify the operation. +func (w *UpdateClusterWaiter) GetClusterId() string { + return w.clusterId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *UpdateClusterWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetClusterRequest{ + pollResp, err := w.poll(ctx, GetClusterRequest{ ClusterId: &w.clusterId, }, opts...) if err != nil { @@ -2101,7 +1876,7 @@ func (w *UpdateClusterWaiter) Done(ctx context.Context, opts ...call.Option) (bo func (w *UpdateClusterWaiter) Wait(ctx context.Context, opts ...lro.Option) (*ClusterInfo, error) { var result *ClusterInfo poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetClusterRequest{ + pollResp, err := w.poll(ctx, GetClusterRequest{ ClusterId: &w.clusterId, }) if err != nil { @@ -2138,8 +1913,8 @@ func (w *UpdateClusterWaiter) Wait(ctx context.Context, opts ...lro.Option) (*Cl // enforcement, the cluster will no longer update on the next termination or // restart. Pending enforcements cannot be canceled when a cluster is in // `TERMINATING` state. Only workspace admins can cancel pending enforcements. -func (c *internalClient) CancelPendingClusterEnforcement(ctx context.Context, req *CancelPendingClusterEnforcementRequest, opts ...call.Option) (*CancelPendingClusterEnforcementResponse, error) { - wireReq, err := cancelPendingClusterEnforcementRequestToWire(req) +func (c *internalClient) CancelPendingClusterEnforcement(ctx context.Context, req CancelPendingClusterEnforcementRequest, opts ...call.Option) (*CancelPendingClusterEnforcementResponse, error) { + wireReq, err := cancelPendingClusterEnforcementRequestToWire(&req) if err != nil { return nil, err } @@ -2209,8 +1984,8 @@ func (c *internalClient) CancelPendingClusterEnforcement(ctx context.Context, re // Clusters created by the Databricks Jobs, SDP, or Models services cannot be // enforced by this API. Instead, use the "Enforce job policy compliance" API to // enforce policy compliance on jobs. -func (c *internalClient) EnforcePolicyComplianceForCluster(ctx context.Context, req *EnforcePolicyComplianceForClusterRequest, opts ...call.Option) (*EnforcePolicyComplianceForClusterResponse, error) { - wireReq, err := enforcePolicyComplianceForClusterRequestToWire(req) +func (c *internalClient) EnforcePolicyComplianceForCluster(ctx context.Context, req EnforcePolicyComplianceForClusterRequest, opts ...call.Option) (*EnforcePolicyComplianceForClusterResponse, error) { + wireReq, err := enforcePolicyComplianceForClusterRequestToWire(&req) if err != nil { return nil, err } @@ -2276,8 +2051,8 @@ func (c *internalClient) EnforcePolicyComplianceForCluster(ctx context.Context, // Returns the policy compliance status of a cluster. Clusters could be out of // compliance if their policy was updated after the cluster was last edited. -func (c *internalClient) GetPolicyComplianceForCluster(ctx context.Context, req *GetPolicyComplianceForClusterRequest, opts ...call.Option) (*GetPolicyComplianceForClusterResponse, error) { - wireReq, err := getPolicyComplianceForClusterRequestToWire(req) +func (c *internalClient) GetPolicyComplianceForCluster(ctx context.Context, req GetPolicyComplianceForClusterRequest, opts ...call.Option) (*GetPolicyComplianceForClusterResponse, error) { + wireReq, err := getPolicyComplianceForClusterRequestToWire(&req) if err != nil { return nil, err } @@ -2342,8 +2117,8 @@ func (c *internalClient) GetPolicyComplianceForCluster(ctx context.Context, req // Returns the policy compliance status of all clusters that use a given policy. // Clusters could be out of compliance if their policy was updated after the // cluster was last edited. -func (c *internalClient) ListClusterComplianceForPolicy(ctx context.Context, req *ListClusterComplianceForPolicyRequest, opts ...call.Option) (*ListClusterComplianceForPolicyResponse, error) { - wireReq, err := listClusterComplianceForPolicyRequestToWire(req) +func (c *internalClient) ListClusterComplianceForPolicy(ctx context.Context, req ListClusterComplianceForPolicyRequest, opts ...call.Option) (*ListClusterComplianceForPolicyResponse, error) { + wireReq, err := listClusterComplianceForPolicyRequestToWire(&req) if err != nil { return nil, err } @@ -2416,7 +2191,7 @@ func (c *internalClient) ListClusterComplianceForPolicy(ctx context.Context, req // // For example: // -// for item, err := range c.ListClusterComplianceForPolicyIter(ctx, &ListClusterComplianceForPolicyRequest{}) { +// for item, err := range c.ListClusterComplianceForPolicyIter(ctx, ListClusterComplianceForPolicyRequest{}) { // if err != nil { // return err // } @@ -2428,16 +2203,13 @@ func (c *internalClient) ListClusterComplianceForPolicy(ctx context.Context, req // // Callers who need custom pagination logic should use // ListClusterComplianceForPolicy directly. -func (c *internalClient) ListClusterComplianceForPolicyIter(ctx context.Context, req *ListClusterComplianceForPolicyRequest, opts ...call.Option) iter.Seq2[*ClusterCompliance, error] { +func (c *internalClient) ListClusterComplianceForPolicyIter(ctx context.Context, req ListClusterComplianceForPolicyRequest, opts ...call.Option) iter.Seq2[*ClusterCompliance, error] { return func(yield func(*ClusterCompliance, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListClusterComplianceForPolicyRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListClusterComplianceForPolicy(ctx, &pageReq, opts...) + resp, err := c.ListClusterComplianceForPolicy(ctx, pageReq, opts...) if err != nil { yield(nil, err) return diff --git a/clusters/v2/genhelper.go b/clusters/v2/genhelper.go old mode 100755 new mode 100644 index 55c4049..85a51e3 --- a/clusters/v2/genhelper.go +++ b/clusters/v2/genhelper.go @@ -12,7 +12,6 @@ import ( "log/slog" "net/http" "net/url" - "strings" "github.com/databricks/sdk-go/auth" "github.com/databricks/sdk-go/core/apierr" @@ -198,46 +197,3 @@ func flattenQueryValue(params url.Values, key string, value any) { params.Add(key, fmt.Sprintf("%v", value)) } } - -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). -type pathBuilder struct { - path strings.Builder - raw strings.Builder -} - -// literal appends a static path segment, identical on the decoded and escaped -// paths. -func (b *pathBuilder) literal(s string) { - b.path.WriteString(s) - b.raw.WriteString(s) -} - -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. -func (b *pathBuilder) singleSegment(v any) { - s := fmt.Sprintf("%v", v) - b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) -} - -// multiSegments appends a multi-segment path parameter: the value spans several -// path segments, so each segment is escaped but the "/" separators are kept. -// The value is formatted with %v so strings, enums, and numbers all work. -func (b *pathBuilder) multiSegments(v any) { - s := fmt.Sprintf("%v", v) - b.path.WriteString(s) - segments := strings.Split(s, "/") - for i, seg := range segments { - segments[i] = url.PathEscape(seg) - } - b.raw.WriteString(strings.Join(segments, "/")) -} - -func (b *pathBuilder) build() (path, rawPath string) { - return b.path.String(), b.raw.String() -} diff --git a/clusters/v2/model.go b/clusters/v2/model.go old mode 100755 new mode 100644 index 6de38c9..c7e9bdf --- a/clusters/v2/model.go +++ b/clusters/v2/model.go @@ -48,22 +48,6 @@ const ( CloudProviderNodeStatus_NotAvailableInRegion CloudProviderNodeStatus = "NotAvailableInRegion" ) -// Possible reasons a cluster might be edited. -type ClusterEditReason string - -const ( - ClusterEditReason_Unspecified ClusterEditReason = "" - // Cluster was initially created. - ClusterEditReason_Creation ClusterEditReason = "CREATION" - // Cluster was manually edited by the user. - ClusterEditReason_ManualEdit ClusterEditReason = "MANUAL_EDIT" - // Cluster was edited as part of a policy enforcement. - ClusterEditReason_PolicyEnforcement ClusterEditReason = "POLICY_ENFORCEMENT" - // Cluster was edited as part of a policy enforcement that was scheduled on the - // next cluster termination / restart. - ClusterEditReason_DeferredPolicyEnforcement ClusterEditReason = "DEFERRED_POLICY_ENFORCEMENT" -) - // The kind of compute described by this compute specification. // // Depending on `kind`, different validations and default values will be @@ -1267,7 +1251,7 @@ type ClusterAttributes struct { // Currently only supported for GCP HYPERDISK_BALANCED disks. RemoteDiskThroughput *int // If set, what the total initial volume size (in GB) of the remote disks should - // be. Currently only supported for GCP HYPERDISK_BALANCED disks. + // be. Supported for GCP. TotalInitialRemoteDiskSize *int // Controls dependency configuration for the cluster. DependencyMode DependencyMode @@ -1489,7 +1473,7 @@ type ClusterInfo struct { // Currently only supported for GCP HYPERDISK_BALANCED disks. RemoteDiskThroughput *int // If set, what the total initial volume size (in GB) of the remote disks should - // be. Currently only supported for GCP HYPERDISK_BALANCED disks. + // be. Supported for GCP. TotalInitialRemoteDiskSize *int // Controls dependency configuration for the cluster. DependencyMode DependencyMode @@ -1676,7 +1660,7 @@ type ClusterInfo_ComputeSpec struct { // Currently only supported for GCP HYPERDISK_BALANCED disks. RemoteDiskThroughput *int // If set, what the total initial volume size (in GB) of the remote disks should - // be. Currently only supported for GCP HYPERDISK_BALANCED disks. + // be. Supported for GCP. TotalInitialRemoteDiskSize *int // Controls dependency configuration for the cluster. DependencyMode DependencyMode @@ -1759,24 +1743,6 @@ type clusterLogConfStorageInfoFieldMaskMetadata struct { *ClusterLogConf_StorageInfo_Volumes } -// Represents a cluster revision. -// -// Only the 100 most recent revisions are stored for each cluster.. -type ClusterRevision struct { - // ID of the cluster revision. - RevisionId *string - // Time when the cluster revision was created. - CreateTime *types.Time - // Settings used to create/edit the cluster. - Settings *ClusterInfo_ComputeSpec - // Reason the cluster was edited. - EditReason ClusterEditReason - // Name of the user who edited this cluster. - EditUser *string - // Whether this is the current revision. - IsCurrent *bool -} - type ClusterSize struct { Size isClusterSize_Size } @@ -1956,7 +1922,7 @@ type CreateClusterRequest struct { // Currently only supported for GCP HYPERDISK_BALANCED disks. RemoteDiskThroughput *int // If set, what the total initial volume size (in GB) of the remote disks should - // be. Currently only supported for GCP HYPERDISK_BALANCED disks. + // be. Supported for GCP. TotalInitialRemoteDiskSize *int // Controls dependency configuration for the cluster. DependencyMode DependencyMode @@ -2188,7 +2154,7 @@ type EditClusterRequest struct { // Currently only supported for GCP HYPERDISK_BALANCED disks. RemoteDiskThroughput *int // If set, what the total initial volume size (in GB) of the remote disks should - // be. Currently only supported for GCP HYPERDISK_BALANCED disks. + // be. Supported for GCP. TotalInitialRemoteDiskSize *int // Controls dependency configuration for the cluster. DependencyMode DependencyMode @@ -2394,7 +2360,7 @@ type EnforcePolicyComplianceForClusterResponse_ClusterSettings struct { // Currently only supported for GCP HYPERDISK_BALANCED disks. RemoteDiskThroughput *int // If set, what the total initial volume size (in GB) of the remote disks should - // be. Currently only supported for GCP HYPERDISK_BALANCED disks. + // be. Supported for GCP. TotalInitialRemoteDiskSize *int // Controls dependency configuration for the cluster. DependencyMode DependencyMode @@ -2555,13 +2521,6 @@ type GetClusterRequest struct { ClusterId *string } -// Request to get a cluster revision by ID.. -type GetClusterRevisionRequest struct { - // The fully qualified resource name of the cluster revision. Format: - // clusters/{cluster_id}/revisions/{revision_id}. - Name *string -} - type GetEventsResponse struct { Events []ClusterEvent // Deprecated: use next_page_token or prev_page_token instead. @@ -2830,25 +2789,6 @@ type ListClusterComplianceForPolicyResponse struct { PrevPageToken *string } -// Request to list cluster revisions.. -type ListClusterRevisionsRequest struct { - // The fully qualified resource name of the parent cluster. Format: - // clusters/{cluster_id}. - Parent *string - // Maximum number of cluster revisions to return per page. - PageSize *int - // Pagination token from a previous list cluster revisions request. - PageToken *string -} - -// Response when listing cluster revisions.. -type ListClusterRevisionsResponse struct { - // Cluster revisions in the current page. - ClusterRevisions []ClusterRevision - // Token for fetching the next page. Empty when there are no more results. - NextPageToken *string -} - type ListClustersRequest struct { // Use next_page_token or prev_page_token returned from the previous request to // list the next or previous page of clusters respectively. @@ -3010,6 +2950,9 @@ type NodeTypeFlexibility struct { // A list of node type IDs to use as fallbacks when the primary node type is // unavailable. AlternateNodeTypeIds []string `fieldmask:"alternate_node_type_ids"` + // The AWS Context ID for EC2 Fleet. When set (non-empty), the value is passed + // to AWS CreateFleet API to create the EC2 Fleet. + AwsContextId *string `fieldmask:"aws_context_id"` } // Represents a pending enforcement on a cluster, which contains the changes to @@ -3098,13 +3041,6 @@ type RestartClusterRequest struct { type RestartClusterResponse struct { } -// Request to roll back cluster.. -type RollbackClusterRequest struct { - // The fully qualified resource name of the cluster revision. Format: - // clusters/{cluster_id}/revisions/{revision_id}. - Name *string -} - // A storage location in Amazon S3. type S3StorageInfo struct { // S3 destination, e.g. `s3://my-bucket/some-prefix` Note that logs will be @@ -3350,7 +3286,7 @@ type UpdateClusterRequest_UpdateClusterResource struct { // Currently only supported for GCP HYPERDISK_BALANCED disks. RemoteDiskThroughput *int `fieldmask:"remote_disk_throughput"` // If set, what the total initial volume size (in GB) of the remote disks should - // be. Currently only supported for GCP HYPERDISK_BALANCED disks. + // be. Supported for GCP. TotalInitialRemoteDiskSize *int `fieldmask:"total_initial_remote_disk_size"` // Controls dependency configuration for the cluster. DependencyMode DependencyMode `fieldmask:"dependency_mode"` diff --git a/clusters/v2/wire.go b/clusters/v2/wire.go old mode 100755 new mode 100644 index 488f309..e9c9020 --- a/clusters/v2/wire.go +++ b/clusters/v2/wire.go @@ -3,11 +3,57 @@ package clusters import ( + "bytes" + "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + func fieldMaskToWire[T any](mask *types.FieldMask[T]) *string { if mask == nil { return nil @@ -346,7 +392,7 @@ func clusterComplianceFromWire(w *clusterComplianceWire) (*ClusterCompliance, er type clusterEventWire struct { ClusterId *string `json:"cluster_id,omitempty"` - Timestamp *int64 `json:"timestamp,omitempty"` + Timestamp *wireInt64 `json:"timestamp,omitempty"` Type ClusterEventType_ClusterEventType `json:"type,omitempty"` Details *eventDetailsWire `json:"details,omitempty"` DataPlaneEventDetails *dataPlaneEventDetailsWire `json:"data_plane_event_details,omitempty"` @@ -356,6 +402,10 @@ func clusterEventFromWire(w *clusterEventWire) (*ClusterEvent, error) { if w == nil { return nil, nil } + timestampPublicValue, err := int64FromWire(w.Timestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ClusterEvent.Timestamp", err) + } detailsPublicValue, err := eventDetailsFromWire(w.Details) if err != nil { return nil, fmt.Errorf("%s: %w", "ClusterEvent.Details", err) @@ -366,7 +416,7 @@ func clusterEventFromWire(w *clusterEventWire) (*ClusterEvent, error) { } return &ClusterEvent{ ClusterId: w.ClusterId, - Timestamp: w.Timestamp, + Timestamp: timestampPublicValue, Type: w.Type, Details: detailsPublicValue, DataPlaneEventDetails: dataPlaneEventDetailsPublicValue, @@ -378,7 +428,7 @@ type clusterInfoWire struct { CreatorUserName *string `json:"creator_user_name,omitempty"` State ClusterState_ClusterState `json:"state,omitempty"` StateMessage *string `json:"state_message,omitempty"` - ClusterMemoryMb *int64 `json:"cluster_memory_mb,omitempty"` + ClusterMemoryMb *wireInt64 `json:"cluster_memory_mb,omitempty"` ClusterCores *float32 `json:"cluster_cores,omitempty"` DefaultTags map[string]string `json:"default_tags,omitempty"` ClusterLogStatus *logSyncStatusWire `json:"cluster_log_status,omitempty"` @@ -386,7 +436,7 @@ type clusterInfoWire struct { Spec *clusterInfo_ComputeSpecWire `json:"spec,omitempty"` Driver *sparkInfo_SparkNodeWire `json:"driver,omitempty"` Executors []sparkInfo_SparkNodeWire `json:"executors,omitempty"` - SparkContextId *int64 `json:"spark_context_id,omitempty"` + SparkContextId *wireInt64 `json:"spark_context_id,omitempty"` JdbcPort *int `json:"jdbc_port,omitempty"` ClusterName *string `json:"cluster_name,omitempty"` SparkVersion *string `json:"spark_version,omitempty"` @@ -420,10 +470,10 @@ type clusterInfoWire struct { RemoteDiskThroughput *int `json:"remote_disk_throughput,omitempty"` TotalInitialRemoteDiskSize *int `json:"total_initial_remote_disk_size,omitempty"` DependencyMode DependencyMode `json:"dependency_mode,omitempty"` - StartTime *int64 `json:"start_time,omitempty"` - TerminatedTime *int64 `json:"terminated_time,omitempty"` - LastStateLossTime *int64 `json:"last_state_loss_time,omitempty"` - LastRestartedTime *int64 `json:"last_restarted_time,omitempty"` + StartTime *wireInt64 `json:"start_time,omitempty"` + TerminatedTime *wireInt64 `json:"terminated_time,omitempty"` + LastStateLossTime *wireInt64 `json:"last_state_loss_time,omitempty"` + LastRestartedTime *wireInt64 `json:"last_restarted_time,omitempty"` NumWorkers *int `json:"num_workers,omitempty"` Autoscale *autoScaleWire `json:"autoscale,omitempty"` } @@ -442,6 +492,10 @@ func clusterInfoFromWire(w *clusterInfoWire) (*ClusterInfo, error) { if sizeMembers > 1 { return nil, fmt.Errorf("%s: multiple oneof members set", "ClusterInfo.Size") } + clusterMemoryMbPublicValue, err := int64FromWire(w.ClusterMemoryMb) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ClusterInfo.ClusterMemoryMb", err) + } clusterLogStatusPublicValue, err := logSyncStatusFromWire(w.ClusterLogStatus) if err != nil { return nil, fmt.Errorf("%s: %w", "ClusterInfo.ClusterLogStatus", err) @@ -462,6 +516,10 @@ func clusterInfoFromWire(w *clusterInfoWire) (*ClusterInfo, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "ClusterInfo.Executors", err) } + sparkContextIdPublicValue, err := int64FromWire(w.SparkContextId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ClusterInfo.SparkContextId", err) + } awsAttributesPublicValue, err := awsAttributesFromWire(w.AwsAttributes) if err != nil { return nil, fmt.Errorf("%s: %w", "ClusterInfo.AwsAttributes", err) @@ -498,6 +556,22 @@ func clusterInfoFromWire(w *clusterInfoWire) (*ClusterInfo, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "ClusterInfo.WorkloadType", err) } + startTimePublicValue, err := int64FromWire(w.StartTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ClusterInfo.StartTime", err) + } + terminatedTimePublicValue, err := int64FromWire(w.TerminatedTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ClusterInfo.TerminatedTime", err) + } + lastStateLossTimePublicValue, err := int64FromWire(w.LastStateLossTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ClusterInfo.LastStateLossTime", err) + } + lastRestartedTimePublicValue, err := int64FromWire(w.LastRestartedTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ClusterInfo.LastRestartedTime", err) + } var sizeSelection isClusterInfo_Size switch { case w.NumWorkers != nil: @@ -514,7 +588,7 @@ func clusterInfoFromWire(w *clusterInfoWire) (*ClusterInfo, error) { CreatorUserName: w.CreatorUserName, State: w.State, StateMessage: w.StateMessage, - ClusterMemoryMb: w.ClusterMemoryMb, + ClusterMemoryMb: clusterMemoryMbPublicValue, ClusterCores: w.ClusterCores, DefaultTags: w.DefaultTags, ClusterLogStatus: clusterLogStatusPublicValue, @@ -522,7 +596,7 @@ func clusterInfoFromWire(w *clusterInfoWire) (*ClusterInfo, error) { Spec: specPublicValue, Driver: driverPublicValue, Executors: executorsPublicValue, - SparkContextId: w.SparkContextId, + SparkContextId: sparkContextIdPublicValue, JdbcPort: w.JdbcPort, ClusterName: w.ClusterName, SparkVersion: w.SparkVersion, @@ -556,10 +630,10 @@ func clusterInfoFromWire(w *clusterInfoWire) (*ClusterInfo, error) { RemoteDiskThroughput: w.RemoteDiskThroughput, TotalInitialRemoteDiskSize: w.TotalInitialRemoteDiskSize, DependencyMode: w.DependencyMode, - StartTime: w.StartTime, - TerminatedTime: w.TerminatedTime, - LastStateLossTime: w.LastStateLossTime, - LastRestartedTime: w.LastRestartedTime, + StartTime: startTimePublicValue, + TerminatedTime: terminatedTimePublicValue, + LastStateLossTime: lastStateLossTimePublicValue, + LastRestartedTime: lastRestartedTimePublicValue, Size: sizeSelection, }, nil } @@ -793,33 +867,6 @@ func clusterLogConfFromWire(w *clusterLogConfWire) (*ClusterLogConf, error) { }, nil } -type clusterRevisionWire struct { - RevisionId *string `json:"revision_id,omitempty"` - CreateTime *types.Time `json:"create_time,omitempty"` - Settings *clusterInfo_ComputeSpecWire `json:"settings,omitempty"` - EditReason ClusterEditReason `json:"edit_reason,omitempty"` - EditUser *string `json:"edit_user,omitempty"` - IsCurrent *bool `json:"is_current,omitempty"` -} - -func clusterRevisionFromWire(w *clusterRevisionWire) (*ClusterRevision, error) { - if w == nil { - return nil, nil - } - settingsPublicValue, err := clusterInfo_ComputeSpecFromWire(w.Settings) - if err != nil { - return nil, fmt.Errorf("%s: %w", "ClusterRevision.Settings", err) - } - return &ClusterRevision{ - RevisionId: w.RevisionId, - CreateTime: w.CreateTime, - Settings: settingsPublicValue, - EditReason: w.EditReason, - EditUser: w.EditUser, - IsCurrent: w.IsCurrent, - }, nil -} - type clusterSizeWire struct { NumWorkers *int `json:"num_workers,omitempty"` Autoscale *autoScaleWire `json:"autoscale,omitempty"` @@ -1012,7 +1059,7 @@ func createClusterResponseFromWire(w *createClusterResponseWire) (*CreateCluster type dataPlaneEventDetailsWire struct { EventType DataPlaneClusterEventType `json:"event_type,omitempty"` - Timestamp *int64 `json:"timestamp,omitempty"` + Timestamp *wireInt64 `json:"timestamp,omitempty"` HostId *string `json:"host_id,omitempty"` ExecutorFailures *int `json:"executor_failures,omitempty"` } @@ -1021,9 +1068,13 @@ func dataPlaneEventDetailsFromWire(w *dataPlaneEventDetailsWire) (*DataPlaneEven if w == nil { return nil, nil } + timestampPublicValue, err := int64FromWire(w.Timestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DataPlaneEventDetails.Timestamp", err) + } return &DataPlaneEventDetails{ EventType: w.EventType, - Timestamp: w.Timestamp, + Timestamp: timestampPublicValue, HostId: w.HostId, ExecutorFailures: w.ExecutorFailures, }, nil @@ -1482,9 +1533,9 @@ type eventDetailsWire struct { Cause ResizeCause_ResizeCause `json:"cause,omitempty"` Reason *terminationReasonWire `json:"reason,omitempty"` User *string `json:"user,omitempty"` - PreviousDiskSize *int64 `json:"previous_disk_size,omitempty"` - DiskSize *int64 `json:"disk_size,omitempty"` - FreeSpace *int64 `json:"free_space,omitempty"` + PreviousDiskSize *wireInt64 `json:"previous_disk_size,omitempty"` + DiskSize *wireInt64 `json:"disk_size,omitempty"` + FreeSpace *wireInt64 `json:"free_space,omitempty"` InstanceId *string `json:"instance_id,omitempty"` DidNotExpandReason *string `json:"did_not_expand_reason,omitempty"` DriverStateMessage *string `json:"driver_state_message,omitempty"` @@ -1519,6 +1570,18 @@ func eventDetailsFromWire(w *eventDetailsWire) (*EventDetails, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "EventDetails.Reason", err) } + previousDiskSizePublicValue, err := int64FromWire(w.PreviousDiskSize) + if err != nil { + return nil, fmt.Errorf("%s: %w", "EventDetails.PreviousDiskSize", err) + } + diskSizePublicValue, err := int64FromWire(w.DiskSize) + if err != nil { + return nil, fmt.Errorf("%s: %w", "EventDetails.DiskSize", err) + } + freeSpacePublicValue, err := int64FromWire(w.FreeSpace) + if err != nil { + return nil, fmt.Errorf("%s: %w", "EventDetails.FreeSpace", err) + } initScriptsPublicValue, err := initScriptEventDetailsFromWire(w.InitScripts) if err != nil { return nil, fmt.Errorf("%s: %w", "EventDetails.InitScripts", err) @@ -1533,9 +1596,9 @@ func eventDetailsFromWire(w *eventDetailsWire) (*EventDetails, error) { Cause: w.Cause, Reason: reasonPublicValue, User: w.User, - PreviousDiskSize: w.PreviousDiskSize, - DiskSize: w.DiskSize, - FreeSpace: w.FreeSpace, + PreviousDiskSize: previousDiskSizePublicValue, + DiskSize: diskSizePublicValue, + FreeSpace: freeSpacePublicValue, InstanceId: w.InstanceId, DidNotExpandReason: w.DidNotExpandReason, DriverStateMessage: w.DriverStateMessage, @@ -1628,7 +1691,7 @@ func getClusterRequestToWire(v *GetClusterRequest) (*getClusterRequestWire, erro type getEventsResponseWire struct { Events []clusterEventWire `json:"events,omitempty"` NextPage *listEventsRequestWire `json:"next_page,omitempty"` - TotalCount *int64 `json:"total_count,omitempty"` + TotalCount *wireInt64 `json:"total_count,omitempty"` NextPageToken *string `json:"next_page_token,omitempty"` PrevPageToken *string `json:"prev_page_token,omitempty"` } @@ -1645,10 +1708,14 @@ func getEventsResponseFromWire(w *getEventsResponseWire) (*GetEventsResponse, er if err != nil { return nil, fmt.Errorf("%s: %w", "GetEventsResponse.NextPage", err) } + totalCountPublicValue, err := int64FromWire(w.TotalCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetEventsResponse.TotalCount", err) + } return &GetEventsResponse{ Events: eventsPublicValue, NextPage: nextPagePublicValue, - TotalCount: w.TotalCount, + TotalCount: totalCountPublicValue, NextPageToken: w.NextPageToken, PrevPageToken: w.PrevPageToken, }, nil @@ -2052,42 +2119,6 @@ func listClusterComplianceForPolicyResponseFromWire(w *listClusterComplianceForP }, nil } -type listClusterRevisionsRequestWire struct { - Parent *string `json:"parent,omitempty"` - PageSize *int `json:"page_size,omitempty"` - PageToken *string `json:"page_token,omitempty"` -} - -func listClusterRevisionsRequestToWire(v *ListClusterRevisionsRequest) (*listClusterRevisionsRequestWire, error) { - if v == nil { - return nil, nil - } - return &listClusterRevisionsRequestWire{ - Parent: v.Parent, - PageSize: v.PageSize, - PageToken: v.PageToken, - }, nil -} - -type listClusterRevisionsResponseWire struct { - ClusterRevisions []clusterRevisionWire `json:"cluster_revisions,omitempty"` - NextPageToken *string `json:"next_page_token,omitempty"` -} - -func listClusterRevisionsResponseFromWire(w *listClusterRevisionsResponseWire) (*ListClusterRevisionsResponse, error) { - if w == nil { - return nil, nil - } - clusterRevisionsPublicValue, err := convertSlice(w.ClusterRevisions, clusterRevisionFromWire) - if err != nil { - return nil, fmt.Errorf("%s: %w", "ListClusterRevisionsResponse.ClusterRevisions", err) - } - return &ListClusterRevisionsResponse{ - ClusterRevisions: clusterRevisionsPublicValue, - NextPageToken: w.NextPageToken, - }, nil -} - type listClustersRequestWire struct { PageToken *string `json:"page_token,omitempty"` PageSize *int `json:"page_size,omitempty"` @@ -2126,12 +2157,12 @@ func listClustersResponseFromWire(w *listClustersResponseWire) (*ListClustersRes type listEventsRequestWire struct { ClusterId *string `json:"cluster_id,omitempty"` - StartTime *int64 `json:"start_time,omitempty"` - EndTime *int64 `json:"end_time,omitempty"` + StartTime *wireInt64 `json:"start_time,omitempty"` + EndTime *wireInt64 `json:"end_time,omitempty"` Order GetEventsOrder `json:"order,omitempty"` EventTypes []ClusterEventType_ClusterEventType `json:"event_types,omitempty"` - Offset *int64 `json:"offset,omitempty"` - Limit *int64 `json:"limit,omitempty"` + Offset *wireInt64 `json:"offset,omitempty"` + Limit *wireInt64 `json:"limit,omitempty"` PageToken *string `json:"page_token,omitempty"` PageSize *int `json:"page_size,omitempty"` } @@ -2140,14 +2171,30 @@ func listEventsRequestToWire(v *ListEventsRequest) (*listEventsRequestWire, erro if v == nil { return nil, nil } + startTimeWireValue, err := int64ToWire(v.StartTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListEventsRequest.StartTime", err) + } + endTimeWireValue, err := int64ToWire(v.EndTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListEventsRequest.EndTime", err) + } + offsetWireValue, err := int64ToWire(v.Offset) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListEventsRequest.Offset", err) + } + limitWireValue, err := int64ToWire(v.Limit) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListEventsRequest.Limit", err) + } return &listEventsRequestWire{ ClusterId: v.ClusterId, - StartTime: v.StartTime, - EndTime: v.EndTime, + StartTime: startTimeWireValue, + EndTime: endTimeWireValue, Order: v.Order, EventTypes: v.EventTypes, - Offset: v.Offset, - Limit: v.Limit, + Offset: offsetWireValue, + Limit: limitWireValue, PageToken: v.PageToken, PageSize: v.PageSize, }, nil @@ -2157,14 +2204,30 @@ func listEventsRequestFromWire(w *listEventsRequestWire) (*ListEventsRequest, er if w == nil { return nil, nil } + startTimePublicValue, err := int64FromWire(w.StartTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListEventsRequest.StartTime", err) + } + endTimePublicValue, err := int64FromWire(w.EndTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListEventsRequest.EndTime", err) + } + offsetPublicValue, err := int64FromWire(w.Offset) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListEventsRequest.Offset", err) + } + limitPublicValue, err := int64FromWire(w.Limit) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListEventsRequest.Limit", err) + } return &ListEventsRequest{ ClusterId: w.ClusterId, - StartTime: w.StartTime, - EndTime: w.EndTime, + StartTime: startTimePublicValue, + EndTime: endTimePublicValue, Order: w.Order, EventTypes: w.EventTypes, - Offset: w.Offset, - Limit: w.Limit, + Offset: offsetPublicValue, + Limit: limitPublicValue, PageToken: w.PageToken, PageSize: w.PageSize, }, nil @@ -2235,16 +2298,20 @@ func logAnalyticsInfoFromWire(w *logAnalyticsInfoWire) (*LogAnalyticsInfo, error } type logSyncStatusWire struct { - LastAttempted *int64 `json:"last_attempted,omitempty"` - LastException *string `json:"last_exception,omitempty"` + LastAttempted *wireInt64 `json:"last_attempted,omitempty"` + LastException *string `json:"last_exception,omitempty"` } func logSyncStatusFromWire(w *logSyncStatusWire) (*LogSyncStatus, error) { if w == nil { return nil, nil } + lastAttemptedPublicValue, err := int64FromWire(w.LastAttempted) + if err != nil { + return nil, fmt.Errorf("%s: %w", "LogSyncStatus.LastAttempted", err) + } return &LogSyncStatus{ - LastAttempted: w.LastAttempted, + LastAttempted: lastAttemptedPublicValue, LastException: w.LastException, }, nil } @@ -2331,6 +2398,7 @@ func nodeTypeFromWire(w *nodeTypeWire) (*NodeType, error) { type nodeTypeFlexibilityWire struct { AlternateNodeTypeIds []string `json:"alternate_node_type_ids,omitempty"` + AwsContextId *string `json:"aws_context_id,omitempty"` } func nodeTypeFlexibilityToWire(v *NodeTypeFlexibility) (*nodeTypeFlexibilityWire, error) { @@ -2339,6 +2407,7 @@ func nodeTypeFlexibilityToWire(v *NodeTypeFlexibility) (*nodeTypeFlexibilityWire } return &nodeTypeFlexibilityWire{ AlternateNodeTypeIds: v.AlternateNodeTypeIds, + AwsContextId: v.AwsContextId, }, nil } @@ -2348,6 +2417,7 @@ func nodeTypeFlexibilityFromWire(w *nodeTypeFlexibilityWire) (*NodeTypeFlexibili } return &NodeTypeFlexibility{ AlternateNodeTypeIds: w.AlternateNodeTypeIds, + AwsContextId: w.AwsContextId, }, nil } @@ -2457,19 +2527,6 @@ func restartClusterRequestToWire(v *RestartClusterRequest) (*restartClusterReque }, nil } -type rollbackClusterRequestWire struct { - Name *string `json:"name,omitempty"` -} - -func rollbackClusterRequestToWire(v *RollbackClusterRequest) (*rollbackClusterRequestWire, error) { - if v == nil { - return nil, nil - } - return &rollbackClusterRequestWire{ - Name: v.Name, - }, nil -} - type s3StorageInfoWire struct { Destination *string `json:"destination,omitempty"` Region *string `json:"region,omitempty"` @@ -2515,7 +2572,7 @@ type sparkInfo_SparkNodeWire struct { PublicDns *string `json:"public_dns,omitempty"` NodeId *string `json:"node_id,omitempty"` InstanceId *string `json:"instance_id,omitempty"` - StartTimestamp *int64 `json:"start_timestamp,omitempty"` + StartTimestamp *wireInt64 `json:"start_timestamp,omitempty"` NodeAwsAttributes *sparkInfo_SparkNode_SparkNodeAwsAttributesWire `json:"node_aws_attributes,omitempty"` HostPrivateIp *string `json:"host_private_ip,omitempty"` } @@ -2524,6 +2581,10 @@ func sparkInfo_SparkNodeFromWire(w *sparkInfo_SparkNodeWire) (*SparkInfo_SparkNo if w == nil { return nil, nil } + startTimestampPublicValue, err := int64FromWire(w.StartTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SparkInfo_SparkNode.StartTimestamp", err) + } nodeAwsAttributesPublicValue, err := sparkInfo_SparkNode_SparkNodeAwsAttributesFromWire(w.NodeAwsAttributes) if err != nil { return nil, fmt.Errorf("%s: %w", "SparkInfo_SparkNode.NodeAwsAttributes", err) @@ -2533,7 +2594,7 @@ func sparkInfo_SparkNodeFromWire(w *sparkInfo_SparkNodeWire) (*SparkInfo_SparkNo PublicDns: w.PublicDns, NodeId: w.NodeId, InstanceId: w.InstanceId, - StartTimestamp: w.StartTimestamp, + StartTimestamp: startTimestampPublicValue, NodeAwsAttributes: nodeAwsAttributesPublicValue, HostPrivateIp: w.HostPrivateIp, }, nil diff --git a/commandexecution/CHANGELOG.md b/commandexecution/CHANGELOG.md index 6224c04..19f237c 100644 --- a/commandexecution/CHANGELOG.md +++ b/commandexecution/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/commandexecution/go.mod b/commandexecution/go.mod index ab97988..0c53da4 100644 --- a/commandexecution/go.mod +++ b/commandexecution/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/commandexecution/internal/version.go b/commandexecution/internal/version.go index 4627257..52b8ed5 100644 --- a/commandexecution/internal/version.go +++ b/commandexecution/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-commandexecution" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/commandexecution/v2/client.go b/commandexecution/v2/client.go old mode 100755 new mode 100644 index 76f1fd2..f33f8ff --- a/commandexecution/v2/client.go +++ b/commandexecution/v2/client.go @@ -78,8 +78,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Cancels a currently running command within an execution context. // // The command ID is obtained from a prior successful call to __execute__. -func (c *internalClient) cancelBase(ctx context.Context, req *CancelCommandRequest, opts ...call.Option) (*CancelResponse, error) { - wireReq, err := cancelCommandRequestToWire(req) +func (c *internalClient) cancelBase(ctx context.Context, req CancelCommandRequest, opts ...call.Option) (*CancelResponse, error) { + wireReq, err := cancelCommandRequestToWire(&req) if err != nil { return nil, err } @@ -140,7 +140,7 @@ func (c *internalClient) cancelBase(ctx context.Context, req *CancelCommandReque // Cancels a currently running command within an execution context. // // The command ID is obtained from a prior successful call to __execute__. -func (c *internalClient) Cancel(ctx context.Context, req *CancelCommandRequest, opts ...call.Option) (*CancelWaiter, error) { +func (c *internalClient) Cancel(ctx context.Context, req CancelCommandRequest, opts ...call.Option) (*CancelWaiter, error) { if req.ClusterId == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "ClusterId") } @@ -167,15 +167,30 @@ func (c *internalClient) Cancel(ctx context.Context, req *CancelCommandRequest, // CancelWaiter tracks the state of the operation started by Cancel. type CancelWaiter struct { - poll func(context.Context, *GetCommandStatusRequest, ...call.Option) (*GetCommandStatusResponse, error) + poll func(context.Context, GetCommandStatusRequest, ...call.Option) (*GetCommandStatusResponse, error) clusterId string contextId string commandId string } +// GetClusterId returns the ClusterId value used to identify the operation. +func (w *CancelWaiter) GetClusterId() string { + return w.clusterId +} + +// GetContextId returns the ContextId value used to identify the operation. +func (w *CancelWaiter) GetContextId() string { + return w.contextId +} + +// GetCommandId returns the CommandId value used to identify the operation. +func (w *CancelWaiter) GetCommandId() string { + return w.commandId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *CancelWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetCommandStatusRequest{ + pollResp, err := w.poll(ctx, GetCommandStatusRequest{ ClusterId: &w.clusterId, ContextId: &w.contextId, CommandId: &w.commandId, @@ -202,7 +217,7 @@ func (w *CancelWaiter) Done(ctx context.Context, opts ...call.Option) (bool, err func (w *CancelWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GetCommandStatusResponse, error) { var result *GetCommandStatusResponse poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetCommandStatusRequest{ + pollResp, err := w.poll(ctx, GetCommandStatusRequest{ ClusterId: &w.clusterId, ContextId: &w.contextId, CommandId: &w.commandId, @@ -240,8 +255,8 @@ func (w *CancelWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GetComman // Creates an execution context for running cluster commands. // // If successful, this method returns the ID of the new execution context. -func (c *internalClient) createBase(ctx context.Context, req *CreateContextRequest, opts ...call.Option) (*CreateResponse, error) { - wireReq, err := createContextRequestToWire(req) +func (c *internalClient) createBase(ctx context.Context, req CreateContextRequest, opts ...call.Option) (*CreateResponse, error) { + wireReq, err := createContextRequestToWire(&req) if err != nil { return nil, err } @@ -308,7 +323,7 @@ func (c *internalClient) createBase(ctx context.Context, req *CreateContextReque // Creates an execution context for running cluster commands. // // If successful, this method returns the ID of the new execution context. -func (c *internalClient) Create(ctx context.Context, req *CreateContextRequest, opts ...call.Option) (*CreateWaiter, error) { +func (c *internalClient) Create(ctx context.Context, req CreateContextRequest, opts ...call.Option) (*CreateWaiter, error) { if req.ClusterId == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "ClusterId") } @@ -329,14 +344,24 @@ func (c *internalClient) Create(ctx context.Context, req *CreateContextRequest, // CreateWaiter tracks the state of the operation started by Create. type CreateWaiter struct { - poll func(context.Context, *GetContextStatusRequest, ...call.Option) (*GetContextStatusResponse, error) + poll func(context.Context, GetContextStatusRequest, ...call.Option) (*GetContextStatusResponse, error) clusterId string contextId string } +// GetClusterId returns the ClusterId value used to identify the operation. +func (w *CreateWaiter) GetClusterId() string { + return w.clusterId +} + +// GetContextId returns the ContextId value used to identify the operation. +func (w *CreateWaiter) GetContextId() string { + return w.contextId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *CreateWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetContextStatusRequest{ + pollResp, err := w.poll(ctx, GetContextStatusRequest{ ClusterId: &w.clusterId, ContextId: &w.contextId, }, opts...) @@ -362,7 +387,7 @@ func (w *CreateWaiter) Done(ctx context.Context, opts ...call.Option) (bool, err func (w *CreateWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GetContextStatusResponse, error) { var result *GetContextStatusResponse poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetContextStatusRequest{ + pollResp, err := w.poll(ctx, GetContextStatusRequest{ ClusterId: &w.clusterId, ContextId: &w.contextId, }) @@ -394,8 +419,8 @@ func (w *CreateWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GetContex } // Deletes an execution context. -func (c *internalClient) Destroy(ctx context.Context, req *DestroyContextRequest, opts ...call.Option) (*DestroyResponse, error) { - wireReq, err := destroyContextRequestToWire(req) +func (c *internalClient) Destroy(ctx context.Context, req DestroyContextRequest, opts ...call.Option) (*DestroyResponse, error) { + wireReq, err := destroyContextRequestToWire(&req) if err != nil { return nil, err } @@ -458,8 +483,8 @@ func (c *internalClient) Destroy(ctx context.Context, req *DestroyContextRequest // // If successful, it returns an ID for tracking the status of the command's // execution. -func (c *internalClient) executeBase(ctx context.Context, req *ExecuteCommandRequest, opts ...call.Option) (*CreateResponse, error) { - wireReq, err := executeCommandRequestToWire(req) +func (c *internalClient) executeBase(ctx context.Context, req ExecuteCommandRequest, opts ...call.Option) (*CreateResponse, error) { + wireReq, err := executeCommandRequestToWire(&req) if err != nil { return nil, err } @@ -528,7 +553,7 @@ func (c *internalClient) executeBase(ctx context.Context, req *ExecuteCommandReq // // If successful, it returns an ID for tracking the status of the command's // execution. -func (c *internalClient) Execute(ctx context.Context, req *ExecuteCommandRequest, opts ...call.Option) (*ExecuteWaiter, error) { +func (c *internalClient) Execute(ctx context.Context, req ExecuteCommandRequest, opts ...call.Option) (*ExecuteWaiter, error) { if req.ClusterId == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "ClusterId") } @@ -554,15 +579,30 @@ func (c *internalClient) Execute(ctx context.Context, req *ExecuteCommandRequest // ExecuteWaiter tracks the state of the operation started by Execute. type ExecuteWaiter struct { - poll func(context.Context, *GetCommandStatusRequest, ...call.Option) (*GetCommandStatusResponse, error) + poll func(context.Context, GetCommandStatusRequest, ...call.Option) (*GetCommandStatusResponse, error) clusterId string contextId string commandId string } +// GetClusterId returns the ClusterId value used to identify the operation. +func (w *ExecuteWaiter) GetClusterId() string { + return w.clusterId +} + +// GetContextId returns the ContextId value used to identify the operation. +func (w *ExecuteWaiter) GetContextId() string { + return w.contextId +} + +// GetCommandId returns the CommandId value used to identify the operation. +func (w *ExecuteWaiter) GetCommandId() string { + return w.commandId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *ExecuteWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetCommandStatusRequest{ + pollResp, err := w.poll(ctx, GetCommandStatusRequest{ ClusterId: &w.clusterId, ContextId: &w.contextId, CommandId: &w.commandId, @@ -589,7 +629,7 @@ func (w *ExecuteWaiter) Done(ctx context.Context, opts ...call.Option) (bool, er func (w *ExecuteWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GetCommandStatusResponse, error) { var result *GetCommandStatusResponse poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetCommandStatusRequest{ + pollResp, err := w.poll(ctx, GetCommandStatusRequest{ ClusterId: &w.clusterId, ContextId: &w.contextId, CommandId: &w.commandId, @@ -625,8 +665,8 @@ func (w *ExecuteWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GetComma // command. // // The command ID is obtained from a prior successful call to __execute__. -func (c *internalClient) GetCommandStatus(ctx context.Context, req *GetCommandStatusRequest, opts ...call.Option) (*GetCommandStatusResponse, error) { - wireReq, err := getCommandStatusRequestToWire(req) +func (c *internalClient) GetCommandStatus(ctx context.Context, req GetCommandStatusRequest, opts ...call.Option) (*GetCommandStatusResponse, error) { + wireReq, err := getCommandStatusRequestToWire(&req) if err != nil { return nil, err } @@ -695,8 +735,8 @@ func (c *internalClient) GetCommandStatus(ctx context.Context, req *GetCommandSt } // Gets the status for an execution context. -func (c *internalClient) GetContextStatus(ctx context.Context, req *GetContextStatusRequest, opts ...call.Option) (*GetContextStatusResponse, error) { - wireReq, err := getContextStatusRequestToWire(req) +func (c *internalClient) GetContextStatus(ctx context.Context, req GetContextStatusRequest, opts ...call.Option) (*GetContextStatusResponse, error) { + wireReq, err := getContextStatusRequestToWire(&req) if err != nil { return nil, err } diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 6224c04..19f237c 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/core/internal/version.go b/core/internal/version.go index cd601bf..a23915e 100644 --- a/core/internal/version.go +++ b/core/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-core" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/core/profiles/profiles.go b/core/profiles/profiles.go index 526eb6d..024d1d1 100644 --- a/core/profiles/profiles.go +++ b/core/profiles/profiles.go @@ -97,6 +97,10 @@ type Profile struct { // AccountID is the Databricks Account ID for Accounts API. AccountID string + // GroupID is the ID of the group whose role is assumed when obtaining + // OAuth tokens. + GroupID string + // Token is the personal access token for PAT authentication. Token Secret @@ -363,6 +367,12 @@ var properties = []property{ set: func(p *Profile, v string) error { p.AccountID = v; return nil }, get: func(p *Profile) string { return p.AccountID }, }, + { + envVar: "DATABRICKS_GROUP_ID", + iniKey: "group_id", + set: func(p *Profile, v string) error { p.GroupID = v; return nil }, + get: func(p *Profile) string { return p.GroupID }, + }, { envVar: "DATABRICKS_TOKEN", iniKey: "token", diff --git a/core/profiles/profiles_test.go b/core/profiles/profiles_test.go index 0875035..53ac1b3 100644 --- a/core/profiles/profiles_test.go +++ b/core/profiles/profiles_test.go @@ -203,6 +203,28 @@ func TestResolve(t *testing.T) { WarehouseID: "abc123def456", }, }, + { + name: "groupIDEnvOverridesFile", + opts: []ResolveOption{ + WithFile("testdata/databrickscfg_group_id"), + WithProfile("workspace"), + WithEnv(), + }, + env: map[string]string{ + "DATABRICKS_GROUP_ID": "env-group-id", + }, + want: &Profile{ + Name: "workspace", + Host: "https://workspace.cloud.databricks.com", + Token: Secret("workspace-token"), + AccountID: "acc-123", + ClientID: "client-abc", + ClientSecret: Secret("secret-xyz"), + ClusterID: "0123-456789-abcdef", + WarehouseID: "abc123def456", + GroupID: "env-group-id", + }, + }, { name: "noOptions", env: map[string]string{ @@ -490,9 +512,10 @@ func TestProfile_SaveToFile(t *testing.T) { }{ { desc: "known fields are written to the ini file", - profile: &Profile{Name: "test", Host: "https://saved.cloud.databricks.com", Token: Secret("saved-token"), ClientID: "saved-client-id"}, + profile: &Profile{Name: "test", Host: "https://saved.cloud.databricks.com", GroupID: "saved-group-id", Token: Secret("saved-token"), ClientID: "saved-client-id"}, want: `[test] host = https://saved.cloud.databricks.com +group_id = saved-group-id token = saved-token client_id = saved-client-id `, @@ -610,7 +633,7 @@ func TestProfile_SaveToFile_emptyPath(t *testing.T) { func TestProfile_SaveToFile_roundTrip(t *testing.T) { resetEnv(t) - src := "testdata/databrickscfg" + src := "testdata/databrickscfg_group_id" p, err := Resolve(WithFile(src), WithProfile("workspace")) if err != nil { t.Fatalf("Resolve() error: %v", err) diff --git a/core/profiles/testdata/databrickscfg_group_id b/core/profiles/testdata/databrickscfg_group_id new file mode 100644 index 0000000..a792dd2 --- /dev/null +++ b/core/profiles/testdata/databrickscfg_group_id @@ -0,0 +1,32 @@ +[DEFAULT] +host = https://default.cloud.databricks.com +token = default-token + +[workspace] +host = https://workspace.cloud.databricks.com +token = workspace-token +account_id = acc-123 +client_id = client-abc +client_secret = secret-xyz +cluster_id = 0123-456789-abcdef +warehouse_id = abc123def456 +group_id = group-id + +[azure] +host = https://adb-123.azuredatabricks.net +azure_client_id = az-client-id +azure_client_secret = az-client-secret +azure_tenant_id = az-tenant-id +azure_workspace_resource_id = /subscriptions/sub-id/resourceGroups/rg/providers/Microsoft.Databricks/workspaces/ws + +[hash-in-value] +host = https://hash.cloud.databricks.com +token = abc#def#ghi +client_secret = secret#with#hashes + +[extra-keys] +host = https://extra.cloud.databricks.com +custom_key = custom-value +another_key = another-value + +[empty] diff --git a/customllms/CHANGELOG.md b/customllms/CHANGELOG.md index 6224c04..19f237c 100644 --- a/customllms/CHANGELOG.md +++ b/customllms/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/customllms/go.mod b/customllms/go.mod index 9302662..60463cd 100644 --- a/customllms/go.mod +++ b/customllms/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/customllms/internal/version.go b/customllms/internal/version.go index 1b168ad..75a3511 100644 --- a/customllms/internal/version.go +++ b/customllms/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-customllms" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/customllms/v1/client.go b/customllms/v1/client.go old mode 100755 new mode 100644 index aadd512..77f6df8 --- a/customllms/v1/client.go +++ b/customllms/v1/client.go @@ -74,8 +74,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Cancel a Custom LLM Optimization Run. -func (c *internalClient) CancelCustomLlmOptimizationRun(ctx context.Context, req *CancelCustomLlmOptimizationRunRequest, opts ...call.Option) error { - wireReq, err := cancelCustomLlmOptimizationRunRequestToWire(req) +func (c *internalClient) CancelCustomLlmOptimizationRun(ctx context.Context, req CancelCustomLlmOptimizationRunRequest, opts ...call.Option) error { + wireReq, err := cancelCustomLlmOptimizationRunRequestToWire(&req) if err != nil { return err } @@ -96,7 +96,11 @@ func (c *internalClient) CancelCustomLlmOptimizationRun(ctx context.Context, req } pb := pathBuilder{} pb.literal("/api/2.0/custom-llms/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } pb.literal("/optimize/cancel") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -135,8 +139,8 @@ func (c *internalClient) CancelCustomLlmOptimizationRun(ctx context.Context, req } // Create a Custom LLM. -func (c *internalClient) CreateCustomLlm(ctx context.Context, req *CreateCustomLlmRequest, opts ...call.Option) (*CustomLlm, error) { - wireReq, err := createCustomLlmRequestToWire(req) +func (c *internalClient) CreateCustomLlm(ctx context.Context, req CreateCustomLlmRequest, opts ...call.Option) (*CustomLlm, error) { + wireReq, err := createCustomLlmRequestToWire(&req) if err != nil { return nil, err } @@ -201,7 +205,7 @@ func (c *internalClient) CreateCustomLlm(ctx context.Context, req *CreateCustomL } // Delete a Custom LLM. -func (c *internalClient) DeleteCustomLlm(ctx context.Context, req *DeleteCustomLlmRequest, opts ...call.Option) error { +func (c *internalClient) DeleteCustomLlm(ctx context.Context, req DeleteCustomLlmRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -215,7 +219,11 @@ func (c *internalClient) DeleteCustomLlm(ctx context.Context, req *DeleteCustomL } pb := pathBuilder{} pb.literal("/api/2.0/custom-llms/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -252,7 +260,7 @@ func (c *internalClient) DeleteCustomLlm(ctx context.Context, req *DeleteCustomL } // Get a Custom LLM. -func (c *internalClient) GetCustomLlm(ctx context.Context, req *GetCustomLlmRequest, opts ...call.Option) (*CustomLlm, error) { +func (c *internalClient) GetCustomLlm(ctx context.Context, req GetCustomLlmRequest, opts ...call.Option) (*CustomLlm, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -266,7 +274,11 @@ func (c *internalClient) GetCustomLlm(ctx context.Context, req *GetCustomLlmRequ } pb := pathBuilder{} pb.literal("/api/2.0/custom-llms/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -312,8 +324,8 @@ func (c *internalClient) GetCustomLlm(ctx context.Context, req *GetCustomLlmRequ } // Start a Custom LLM Optimization Run. -func (c *internalClient) StartCustomLlmOptimizationRun(ctx context.Context, req *StartCustomLlmOptimizationRunRequest, opts ...call.Option) (*CustomLlm, error) { - wireReq, err := startCustomLlmOptimizationRunRequestToWire(req) +func (c *internalClient) StartCustomLlmOptimizationRun(ctx context.Context, req StartCustomLlmOptimizationRunRequest, opts ...call.Option) (*CustomLlm, error) { + wireReq, err := startCustomLlmOptimizationRunRequestToWire(&req) if err != nil { return nil, err } @@ -334,7 +346,11 @@ func (c *internalClient) StartCustomLlmOptimizationRun(ctx context.Context, req } pb := pathBuilder{} pb.literal("/api/2.0/custom-llms/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } pb.literal("/optimize") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -382,8 +398,8 @@ func (c *internalClient) StartCustomLlmOptimizationRun(ctx context.Context, req } // Update a Custom LLM. -func (c *internalClient) UpdateCustomLlm(ctx context.Context, req *UpdateCustomLlmRequest, opts ...call.Option) (*CustomLlm, error) { - wireReq, err := updateCustomLlmRequestToWire(req) +func (c *internalClient) UpdateCustomLlm(ctx context.Context, req UpdateCustomLlmRequest, opts ...call.Option) (*CustomLlm, error) { + wireReq, err := updateCustomLlmRequestToWire(&req) if err != nil { return nil, err } @@ -404,7 +420,11 @@ func (c *internalClient) UpdateCustomLlm(ctx context.Context, req *UpdateCustomL } pb := pathBuilder{} pb.literal("/api/2.0/custom-llms/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/customllms/v1/genhelper.go b/customllms/v1/genhelper.go old mode 100755 new mode 100644 index e1d989e..2bc1751 --- a/customllms/v1/genhelper.go +++ b/customllms/v1/genhelper.go @@ -144,11 +144,12 @@ func executeCall(ctx context.Context, op func(context.Context) error, opts []cal return ops.Execute(ctx, op, opsOpts...) } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -161,13 +162,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/database/CHANGELOG.md b/database/CHANGELOG.md index 6224c04..19f237c 100644 --- a/database/CHANGELOG.md +++ b/database/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/database/go.mod b/database/go.mod index e912db9..a8e2921 100644 --- a/database/go.mod +++ b/database/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/database/internal/version.go b/database/internal/version.go index 250e458..90adc61 100644 --- a/database/internal/version.go +++ b/database/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-database" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/database/v1/client.go b/database/v1/client.go old mode 100755 new mode 100644 index eb81de9..dd91a16 --- a/database/v1/client.go +++ b/database/v1/client.go @@ -77,8 +77,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Create a Database Catalog. -func (c *internalClient) CreateDatabaseCatalog(ctx context.Context, req *CreateDatabaseCatalogRequest, opts ...call.Option) (*DatabaseCatalog, error) { - wireReq, err := createDatabaseCatalogRequestToWire(req) +func (c *internalClient) CreateDatabaseCatalog(ctx context.Context, req CreateDatabaseCatalogRequest, opts ...call.Option) (*DatabaseCatalog, error) { + wireReq, err := createDatabaseCatalogRequestToWire(&req) if err != nil { return nil, err } @@ -143,8 +143,8 @@ func (c *internalClient) CreateDatabaseCatalog(ctx context.Context, req *CreateD } // Create a Database Instance. -func (c *internalClient) createDatabaseInstanceBase(ctx context.Context, req *CreateDatabaseInstanceRequest, opts ...call.Option) (*DatabaseInstance, error) { - wireReq, err := createDatabaseInstanceRequestToWire(req) +func (c *internalClient) createDatabaseInstanceBase(ctx context.Context, req CreateDatabaseInstanceRequest, opts ...call.Option) (*DatabaseInstance, error) { + wireReq, err := createDatabaseInstanceRequestToWire(&req) if err != nil { return nil, err } @@ -209,7 +209,7 @@ func (c *internalClient) createDatabaseInstanceBase(ctx context.Context, req *Cr } // Create a Database Instance. -func (c *internalClient) CreateDatabaseInstance(ctx context.Context, req *CreateDatabaseInstanceRequest, opts ...call.Option) (*CreateDatabaseInstanceWaiter, error) { +func (c *internalClient) CreateDatabaseInstance(ctx context.Context, req CreateDatabaseInstanceRequest, opts ...call.Option) (*CreateDatabaseInstanceWaiter, error) { resp, err := c.createDatabaseInstanceBase(ctx, req, opts...) if err != nil { return nil, err @@ -225,13 +225,18 @@ func (c *internalClient) CreateDatabaseInstance(ctx context.Context, req *Create // CreateDatabaseInstanceWaiter tracks the state of the operation started by CreateDatabaseInstance. type CreateDatabaseInstanceWaiter struct { - poll func(context.Context, *GetDatabaseInstanceRequest, ...call.Option) (*DatabaseInstance, error) + poll func(context.Context, GetDatabaseInstanceRequest, ...call.Option) (*DatabaseInstance, error) name string } +// GetName returns the Name value used to identify the operation. +func (w *CreateDatabaseInstanceWaiter) GetName() string { + return w.name +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *CreateDatabaseInstanceWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetDatabaseInstanceRequest{ + pollResp, err := w.poll(ctx, GetDatabaseInstanceRequest{ Name: &w.name, }, opts...) if err != nil { @@ -256,7 +261,7 @@ func (w *CreateDatabaseInstanceWaiter) Done(ctx context.Context, opts ...call.Op func (w *CreateDatabaseInstanceWaiter) Wait(ctx context.Context, opts ...lro.Option) (*DatabaseInstance, error) { var result *DatabaseInstance poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetDatabaseInstanceRequest{ + pollResp, err := w.poll(ctx, GetDatabaseInstanceRequest{ Name: &w.name, }) if err != nil { @@ -284,8 +289,8 @@ func (w *CreateDatabaseInstanceWaiter) Wait(ctx context.Context, opts ...lro.Opt } // Create a role for a Database Instance. -func (c *internalClient) CreateDatabaseInstanceRole(ctx context.Context, req *CreateDatabaseInstanceRoleRequest, opts ...call.Option) (*DatabaseInstanceRole, error) { - wireReq, err := createDatabaseInstanceRoleRequestToWire(req) +func (c *internalClient) CreateDatabaseInstanceRole(ctx context.Context, req CreateDatabaseInstanceRoleRequest, opts ...call.Option) (*DatabaseInstanceRole, error) { + wireReq, err := createDatabaseInstanceRoleRequestToWire(&req) if err != nil { return nil, err } @@ -306,7 +311,11 @@ func (c *internalClient) CreateDatabaseInstanceRole(ctx context.Context, req *Cr } pb := pathBuilder{} pb.literal("/api/2.0/database/instances/") - pb.singleSegment(*req.InstanceName) + if req.InstanceName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.InstanceName) + } pb.literal("/roles") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -359,8 +368,8 @@ func (c *internalClient) CreateDatabaseInstanceRole(ctx context.Context, req *Cr // Create a Database Table. Useful for registering pre-existing PG tables in UC. // See CreateSyncedDatabaseTable for creating synced tables in PG from a source // table in UC. -func (c *internalClient) CreateDatabaseTable(ctx context.Context, req *CreateDatabaseTableRequest, opts ...call.Option) (*DatabaseTable, error) { - wireReq, err := createDatabaseTableRequestToWire(req) +func (c *internalClient) CreateDatabaseTable(ctx context.Context, req CreateDatabaseTableRequest, opts ...call.Option) (*DatabaseTable, error) { + wireReq, err := createDatabaseTableRequestToWire(&req) if err != nil { return nil, err } @@ -425,8 +434,8 @@ func (c *internalClient) CreateDatabaseTable(ctx context.Context, req *CreateDat } // Create a Synced Database Table. -func (c *internalClient) CreateSyncedDatabaseTable(ctx context.Context, req *CreateSyncedDatabaseTableRequest, opts ...call.Option) (*SyncedDatabaseTable, error) { - wireReq, err := createSyncedDatabaseTableRequestToWire(req) +func (c *internalClient) CreateSyncedDatabaseTable(ctx context.Context, req CreateSyncedDatabaseTableRequest, opts ...call.Option) (*SyncedDatabaseTable, error) { + wireReq, err := createSyncedDatabaseTableRequestToWire(&req) if err != nil { return nil, err } @@ -491,7 +500,7 @@ func (c *internalClient) CreateSyncedDatabaseTable(ctx context.Context, req *Cre } // Delete a Database Catalog. -func (c *internalClient) DeleteDatabaseCatalog(ctx context.Context, req *DeleteDatabaseCatalogRequest, opts ...call.Option) error { +func (c *internalClient) DeleteDatabaseCatalog(ctx context.Context, req DeleteDatabaseCatalogRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -505,7 +514,11 @@ func (c *internalClient) DeleteDatabaseCatalog(ctx context.Context, req *DeleteD } pb := pathBuilder{} pb.literal("/api/2.0/database/catalogs/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -542,8 +555,8 @@ func (c *internalClient) DeleteDatabaseCatalog(ctx context.Context, req *DeleteD } // Delete a Database Instance. -func (c *internalClient) DeleteDatabaseInstance(ctx context.Context, req *DeleteDatabaseInstanceRequest, opts ...call.Option) error { - wireReq, err := deleteDatabaseInstanceRequestToWire(req) +func (c *internalClient) DeleteDatabaseInstance(ctx context.Context, req DeleteDatabaseInstanceRequest, opts ...call.Option) error { + wireReq, err := deleteDatabaseInstanceRequestToWire(&req) if err != nil { return err } @@ -560,7 +573,11 @@ func (c *internalClient) DeleteDatabaseInstance(ctx context.Context, req *Delete } pb := pathBuilder{} pb.literal("/api/2.0/database/instances/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "force", wireReq.Force); err != nil { @@ -603,8 +620,8 @@ func (c *internalClient) DeleteDatabaseInstance(ctx context.Context, req *Delete } // Deletes a role for a Database Instance. -func (c *internalClient) DeleteDatabaseInstanceRole(ctx context.Context, req *DeleteDatabaseInstanceRoleRequest, opts ...call.Option) error { - wireReq, err := deleteDatabaseInstanceRoleRequestToWire(req) +func (c *internalClient) DeleteDatabaseInstanceRole(ctx context.Context, req DeleteDatabaseInstanceRoleRequest, opts ...call.Option) error { + wireReq, err := deleteDatabaseInstanceRoleRequestToWire(&req) if err != nil { return err } @@ -621,9 +638,17 @@ func (c *internalClient) DeleteDatabaseInstanceRole(ctx context.Context, req *De } pb := pathBuilder{} pb.literal("/api/2.0/database/instances/") - pb.singleSegment(*req.InstanceName) + if req.InstanceName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.InstanceName) + } pb.literal("/roles/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "reassign_owned_to", wireReq.ReassignOwnedTo); err != nil { @@ -666,7 +691,7 @@ func (c *internalClient) DeleteDatabaseInstanceRole(ctx context.Context, req *De } // Delete a Database Table. -func (c *internalClient) DeleteDatabaseTable(ctx context.Context, req *DeleteDatabaseTableRequest, opts ...call.Option) error { +func (c *internalClient) DeleteDatabaseTable(ctx context.Context, req DeleteDatabaseTableRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -680,7 +705,11 @@ func (c *internalClient) DeleteDatabaseTable(ctx context.Context, req *DeleteDat } pb := pathBuilder{} pb.literal("/api/2.0/database/tables/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -717,8 +746,8 @@ func (c *internalClient) DeleteDatabaseTable(ctx context.Context, req *DeleteDat } // Delete a Synced Database Table. -func (c *internalClient) DeleteSyncedDatabaseTable(ctx context.Context, req *DeleteSyncedDatabaseTableRequest, opts ...call.Option) error { - wireReq, err := deleteSyncedDatabaseTableRequestToWire(req) +func (c *internalClient) DeleteSyncedDatabaseTable(ctx context.Context, req DeleteSyncedDatabaseTableRequest, opts ...call.Option) error { + wireReq, err := deleteSyncedDatabaseTableRequestToWire(&req) if err != nil { return err } @@ -735,7 +764,11 @@ func (c *internalClient) DeleteSyncedDatabaseTable(ctx context.Context, req *Del } pb := pathBuilder{} pb.literal("/api/2.0/database/synced_tables/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "purge_data", wireReq.PurgeData); err != nil { @@ -775,8 +808,8 @@ func (c *internalClient) DeleteSyncedDatabaseTable(ctx context.Context, req *Del } // Find a Database Instance by uid. -func (c *internalClient) FindDatabaseInstanceByUid(ctx context.Context, req *FindDatabaseInstanceByUidRequest, opts ...call.Option) (*DatabaseInstance, error) { - wireReq, err := findDatabaseInstanceByUidRequestToWire(req) +func (c *internalClient) FindDatabaseInstanceByUid(ctx context.Context, req FindDatabaseInstanceByUidRequest, opts ...call.Option) (*DatabaseInstance, error) { + wireReq, err := findDatabaseInstanceByUidRequestToWire(&req) if err != nil { return nil, err } @@ -839,8 +872,8 @@ func (c *internalClient) FindDatabaseInstanceByUid(ctx context.Context, req *Fin } // Generates a credential that can be used to access database instances. -func (c *internalClient) GenerateDatabaseCredential(ctx context.Context, req *GenerateDatabaseCredentialRequest, opts ...call.Option) (*DatabaseCredential, error) { - wireReq, err := generateDatabaseCredentialRequestToWire(req) +func (c *internalClient) GenerateDatabaseCredential(ctx context.Context, req GenerateDatabaseCredentialRequest, opts ...call.Option) (*DatabaseCredential, error) { + wireReq, err := generateDatabaseCredentialRequestToWire(&req) if err != nil { return nil, err } @@ -908,7 +941,7 @@ func (c *internalClient) GenerateDatabaseCredential(ctx context.Context, req *Ge } // Get a Database Catalog. -func (c *internalClient) GetDatabaseCatalog(ctx context.Context, req *GetDatabaseCatalogRequest, opts ...call.Option) (*DatabaseCatalog, error) { +func (c *internalClient) GetDatabaseCatalog(ctx context.Context, req GetDatabaseCatalogRequest, opts ...call.Option) (*DatabaseCatalog, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -922,7 +955,11 @@ func (c *internalClient) GetDatabaseCatalog(ctx context.Context, req *GetDatabas } pb := pathBuilder{} pb.literal("/api/2.0/database/catalogs/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -968,7 +1005,7 @@ func (c *internalClient) GetDatabaseCatalog(ctx context.Context, req *GetDatabas } // Get a Database Instance. -func (c *internalClient) GetDatabaseInstance(ctx context.Context, req *GetDatabaseInstanceRequest, opts ...call.Option) (*DatabaseInstance, error) { +func (c *internalClient) GetDatabaseInstance(ctx context.Context, req GetDatabaseInstanceRequest, opts ...call.Option) (*DatabaseInstance, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -982,7 +1019,11 @@ func (c *internalClient) GetDatabaseInstance(ctx context.Context, req *GetDataba } pb := pathBuilder{} pb.literal("/api/2.0/database/instances/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1028,7 +1069,7 @@ func (c *internalClient) GetDatabaseInstance(ctx context.Context, req *GetDataba } // Gets a role for a Database Instance. -func (c *internalClient) GetDatabaseInstanceRole(ctx context.Context, req *GetDatabaseInstanceRoleRequest, opts ...call.Option) (*DatabaseInstanceRole, error) { +func (c *internalClient) GetDatabaseInstanceRole(ctx context.Context, req GetDatabaseInstanceRoleRequest, opts ...call.Option) (*DatabaseInstanceRole, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1042,9 +1083,17 @@ func (c *internalClient) GetDatabaseInstanceRole(ctx context.Context, req *GetDa } pb := pathBuilder{} pb.literal("/api/2.0/database/instances/") - pb.singleSegment(*req.InstanceName) + if req.InstanceName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.InstanceName) + } pb.literal("/roles/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1090,7 +1139,7 @@ func (c *internalClient) GetDatabaseInstanceRole(ctx context.Context, req *GetDa } // Get a Database Table. -func (c *internalClient) GetDatabaseTable(ctx context.Context, req *GetDatabaseTableRequest, opts ...call.Option) (*DatabaseTable, error) { +func (c *internalClient) GetDatabaseTable(ctx context.Context, req GetDatabaseTableRequest, opts ...call.Option) (*DatabaseTable, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1104,7 +1153,11 @@ func (c *internalClient) GetDatabaseTable(ctx context.Context, req *GetDatabaseT } pb := pathBuilder{} pb.literal("/api/2.0/database/tables/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1150,7 +1203,7 @@ func (c *internalClient) GetDatabaseTable(ctx context.Context, req *GetDatabaseT } // Get a Synced Database Table. -func (c *internalClient) GetSyncedDatabaseTable(ctx context.Context, req *GetSyncedDatabaseTableRequest, opts ...call.Option) (*SyncedDatabaseTable, error) { +func (c *internalClient) GetSyncedDatabaseTable(ctx context.Context, req GetSyncedDatabaseTableRequest, opts ...call.Option) (*SyncedDatabaseTable, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1164,7 +1217,11 @@ func (c *internalClient) GetSyncedDatabaseTable(ctx context.Context, req *GetSyn } pb := pathBuilder{} pb.literal("/api/2.0/database/synced_tables/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1210,8 +1267,8 @@ func (c *internalClient) GetSyncedDatabaseTable(ctx context.Context, req *GetSyn } // This API is currently unimplemented, but exposed for Terraform support. -func (c *internalClient) ListDatabaseCatalogs(ctx context.Context, req *ListDatabaseCatalogsRequest, opts ...call.Option) (*ListDatabaseCatalogsResponse, error) { - wireReq, err := listDatabaseCatalogsRequestToWire(req) +func (c *internalClient) ListDatabaseCatalogs(ctx context.Context, req ListDatabaseCatalogsRequest, opts ...call.Option) (*ListDatabaseCatalogsResponse, error) { + wireReq, err := listDatabaseCatalogsRequestToWire(&req) if err != nil { return nil, err } @@ -1228,7 +1285,11 @@ func (c *internalClient) ListDatabaseCatalogs(ctx context.Context, req *ListData } pb := pathBuilder{} pb.literal("/api/2.0/database/instances/") - pb.singleSegment(*req.InstanceName) + if req.InstanceName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.InstanceName) + } pb.literal("/catalogs") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1285,7 +1346,7 @@ func (c *internalClient) ListDatabaseCatalogs(ctx context.Context, req *ListData // // For example: // -// for item, err := range c.ListDatabaseCatalogsIter(ctx, &ListDatabaseCatalogsRequest{}) { +// for item, err := range c.ListDatabaseCatalogsIter(ctx, ListDatabaseCatalogsRequest{}) { // if err != nil { // return err // } @@ -1297,16 +1358,13 @@ func (c *internalClient) ListDatabaseCatalogs(ctx context.Context, req *ListData // // Callers who need custom pagination logic should use // ListDatabaseCatalogs directly. -func (c *internalClient) ListDatabaseCatalogsIter(ctx context.Context, req *ListDatabaseCatalogsRequest, opts ...call.Option) iter.Seq2[*DatabaseCatalog, error] { +func (c *internalClient) ListDatabaseCatalogsIter(ctx context.Context, req ListDatabaseCatalogsRequest, opts ...call.Option) iter.Seq2[*DatabaseCatalog, error] { return func(yield func(*DatabaseCatalog, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListDatabaseCatalogsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListDatabaseCatalogs(ctx, &pageReq, opts...) + resp, err := c.ListDatabaseCatalogs(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1329,8 +1387,8 @@ func (c *internalClient) ListDatabaseCatalogsIter(ctx context.Context, req *List // advance these to PUBLIC_PREVIEW. These APIs will remain effectively // undocumented/UI-only and we'll aim for a new public roles API as part of V2 // PuPr. -func (c *internalClient) ListDatabaseInstanceRoles(ctx context.Context, req *ListDatabaseInstanceRolesRequest, opts ...call.Option) (*ListDatabaseInstanceRolesResponse, error) { - wireReq, err := listDatabaseInstanceRolesRequestToWire(req) +func (c *internalClient) ListDatabaseInstanceRoles(ctx context.Context, req ListDatabaseInstanceRolesRequest, opts ...call.Option) (*ListDatabaseInstanceRolesResponse, error) { + wireReq, err := listDatabaseInstanceRolesRequestToWire(&req) if err != nil { return nil, err } @@ -1347,7 +1405,11 @@ func (c *internalClient) ListDatabaseInstanceRoles(ctx context.Context, req *Lis } pb := pathBuilder{} pb.literal("/api/2.0/database/instances/") - pb.singleSegment(*req.InstanceName) + if req.InstanceName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.InstanceName) + } pb.literal("/roles") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1404,7 +1466,7 @@ func (c *internalClient) ListDatabaseInstanceRoles(ctx context.Context, req *Lis // // For example: // -// for item, err := range c.ListDatabaseInstanceRolesIter(ctx, &ListDatabaseInstanceRolesRequest{}) { +// for item, err := range c.ListDatabaseInstanceRolesIter(ctx, ListDatabaseInstanceRolesRequest{}) { // if err != nil { // return err // } @@ -1416,16 +1478,13 @@ func (c *internalClient) ListDatabaseInstanceRoles(ctx context.Context, req *Lis // // Callers who need custom pagination logic should use // ListDatabaseInstanceRoles directly. -func (c *internalClient) ListDatabaseInstanceRolesIter(ctx context.Context, req *ListDatabaseInstanceRolesRequest, opts ...call.Option) iter.Seq2[*DatabaseInstanceRole, error] { +func (c *internalClient) ListDatabaseInstanceRolesIter(ctx context.Context, req ListDatabaseInstanceRolesRequest, opts ...call.Option) iter.Seq2[*DatabaseInstanceRole, error] { return func(yield func(*DatabaseInstanceRole, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListDatabaseInstanceRolesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListDatabaseInstanceRoles(ctx, &pageReq, opts...) + resp, err := c.ListDatabaseInstanceRoles(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1444,8 +1503,8 @@ func (c *internalClient) ListDatabaseInstanceRolesIter(ctx context.Context, req } // List Database Instances. -func (c *internalClient) ListDatabaseInstances(ctx context.Context, req *ListDatabaseInstancesRequest, opts ...call.Option) (*ListDatabaseInstancesResponse, error) { - wireReq, err := listDatabaseInstancesRequestToWire(req) +func (c *internalClient) ListDatabaseInstances(ctx context.Context, req ListDatabaseInstancesRequest, opts ...call.Option) (*ListDatabaseInstancesResponse, error) { + wireReq, err := listDatabaseInstancesRequestToWire(&req) if err != nil { return nil, err } @@ -1515,7 +1574,7 @@ func (c *internalClient) ListDatabaseInstances(ctx context.Context, req *ListDat // // For example: // -// for item, err := range c.ListDatabaseInstancesIter(ctx, &ListDatabaseInstancesRequest{}) { +// for item, err := range c.ListDatabaseInstancesIter(ctx, ListDatabaseInstancesRequest{}) { // if err != nil { // return err // } @@ -1527,16 +1586,13 @@ func (c *internalClient) ListDatabaseInstances(ctx context.Context, req *ListDat // // Callers who need custom pagination logic should use // ListDatabaseInstances directly. -func (c *internalClient) ListDatabaseInstancesIter(ctx context.Context, req *ListDatabaseInstancesRequest, opts ...call.Option) iter.Seq2[*DatabaseInstance, error] { +func (c *internalClient) ListDatabaseInstancesIter(ctx context.Context, req ListDatabaseInstancesRequest, opts ...call.Option) iter.Seq2[*DatabaseInstance, error] { return func(yield func(*DatabaseInstance, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListDatabaseInstancesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListDatabaseInstances(ctx, &pageReq, opts...) + resp, err := c.ListDatabaseInstances(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1555,8 +1611,8 @@ func (c *internalClient) ListDatabaseInstancesIter(ctx context.Context, req *Lis } // This API is currently unimplemented, but exposed for Terraform support. -func (c *internalClient) ListSyncedDatabaseTables(ctx context.Context, req *ListSyncedDatabaseTablesRequest, opts ...call.Option) (*ListSyncedDatabaseTablesResponse, error) { - wireReq, err := listSyncedDatabaseTablesRequestToWire(req) +func (c *internalClient) ListSyncedDatabaseTables(ctx context.Context, req ListSyncedDatabaseTablesRequest, opts ...call.Option) (*ListSyncedDatabaseTablesResponse, error) { + wireReq, err := listSyncedDatabaseTablesRequestToWire(&req) if err != nil { return nil, err } @@ -1573,7 +1629,11 @@ func (c *internalClient) ListSyncedDatabaseTables(ctx context.Context, req *List } pb := pathBuilder{} pb.literal("/api/2.0/database/instances/") - pb.singleSegment(*req.InstanceName) + if req.InstanceName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.InstanceName) + } pb.literal("/synced_tables") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1630,7 +1690,7 @@ func (c *internalClient) ListSyncedDatabaseTables(ctx context.Context, req *List // // For example: // -// for item, err := range c.ListSyncedDatabaseTablesIter(ctx, &ListSyncedDatabaseTablesRequest{}) { +// for item, err := range c.ListSyncedDatabaseTablesIter(ctx, ListSyncedDatabaseTablesRequest{}) { // if err != nil { // return err // } @@ -1642,16 +1702,13 @@ func (c *internalClient) ListSyncedDatabaseTables(ctx context.Context, req *List // // Callers who need custom pagination logic should use // ListSyncedDatabaseTables directly. -func (c *internalClient) ListSyncedDatabaseTablesIter(ctx context.Context, req *ListSyncedDatabaseTablesRequest, opts ...call.Option) iter.Seq2[*SyncedDatabaseTable, error] { +func (c *internalClient) ListSyncedDatabaseTablesIter(ctx context.Context, req ListSyncedDatabaseTablesRequest, opts ...call.Option) iter.Seq2[*SyncedDatabaseTable, error] { return func(yield func(*SyncedDatabaseTable, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListSyncedDatabaseTablesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListSyncedDatabaseTables(ctx, &pageReq, opts...) + resp, err := c.ListSyncedDatabaseTables(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1670,8 +1727,8 @@ func (c *internalClient) ListSyncedDatabaseTablesIter(ctx context.Context, req * } // This API is currently unimplemented, but exposed for Terraform support. -func (c *internalClient) UpdateDatabaseCatalog(ctx context.Context, req *UpdateDatabaseCatalogRequest, opts ...call.Option) (*DatabaseCatalog, error) { - wireReq, err := updateDatabaseCatalogRequestToWire(req) +func (c *internalClient) UpdateDatabaseCatalog(ctx context.Context, req UpdateDatabaseCatalogRequest, opts ...call.Option) (*DatabaseCatalog, error) { + wireReq, err := updateDatabaseCatalogRequestToWire(&req) if err != nil { return nil, err } @@ -1692,7 +1749,11 @@ func (c *internalClient) UpdateDatabaseCatalog(ctx context.Context, req *UpdateD } pb := pathBuilder{} pb.literal("/api/2.0/database/catalogs/") - pb.singleSegment(*req.DatabaseCatalog.Name) + if req.DatabaseCatalog == nil || req.DatabaseCatalog.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DatabaseCatalog.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -1742,8 +1803,8 @@ func (c *internalClient) UpdateDatabaseCatalog(ctx context.Context, req *UpdateD } // Update a Database Instance. -func (c *internalClient) UpdateDatabaseInstance(ctx context.Context, req *UpdateDatabaseInstanceRequest, opts ...call.Option) (*DatabaseInstance, error) { - wireReq, err := updateDatabaseInstanceRequestToWire(req) +func (c *internalClient) UpdateDatabaseInstance(ctx context.Context, req UpdateDatabaseInstanceRequest, opts ...call.Option) (*DatabaseInstance, error) { + wireReq, err := updateDatabaseInstanceRequestToWire(&req) if err != nil { return nil, err } @@ -1764,7 +1825,11 @@ func (c *internalClient) UpdateDatabaseInstance(ctx context.Context, req *Update } pb := pathBuilder{} pb.literal("/api/2.0/database/instances/") - pb.singleSegment(*req.DatabaseInstance.Name) + if req.DatabaseInstance == nil || req.DatabaseInstance.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DatabaseInstance.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -1814,8 +1879,8 @@ func (c *internalClient) UpdateDatabaseInstance(ctx context.Context, req *Update } // This API is currently unimplemented, but exposed for Terraform support. -func (c *internalClient) UpdateSyncedDatabaseTable(ctx context.Context, req *UpdateSyncedDatabaseTableRequest, opts ...call.Option) (*SyncedDatabaseTable, error) { - wireReq, err := updateSyncedDatabaseTableRequestToWire(req) +func (c *internalClient) UpdateSyncedDatabaseTable(ctx context.Context, req UpdateSyncedDatabaseTableRequest, opts ...call.Option) (*SyncedDatabaseTable, error) { + wireReq, err := updateSyncedDatabaseTableRequestToWire(&req) if err != nil { return nil, err } @@ -1836,7 +1901,11 @@ func (c *internalClient) UpdateSyncedDatabaseTable(ctx context.Context, req *Upd } pb := pathBuilder{} pb.literal("/api/2.0/database/synced_tables/") - pb.singleSegment(*req.SyncedTable.Name) + if req.SyncedTable == nil || req.SyncedTable.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SyncedTable.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { diff --git a/database/v1/genhelper.go b/database/v1/genhelper.go old mode 100755 new mode 100644 index 836d288..112de4f --- a/database/v1/genhelper.go +++ b/database/v1/genhelper.go @@ -213,11 +213,12 @@ func generateRequestID() string { return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:16]) } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -230,13 +231,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/database/v1/wire.go b/database/v1/wire.go old mode 100755 new mode 100644 index 9944272..7ca429d --- a/database/v1/wire.go +++ b/database/v1/wire.go @@ -3,11 +3,57 @@ package database import ( + "bytes" + "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + func fieldMaskToWire[T any](mask *types.FieldMask[T]) *string { if mask == nil { return nil @@ -503,7 +549,7 @@ func deleteSyncedDatabaseTableRequestToWire(v *DeleteSyncedDatabaseTableRequest) } type deltaTableSyncInfoWire struct { - DeltaCommitVersion *int64 `json:"delta_commit_version,omitempty"` + DeltaCommitVersion *wireInt64 `json:"delta_commit_version,omitempty"` DeltaCommitTimestamp *types.Time `json:"delta_commit_timestamp,omitempty"` } @@ -511,8 +557,12 @@ func deltaTableSyncInfoToWire(v *DeltaTableSyncInfo) (*deltaTableSyncInfoWire, e if v == nil { return nil, nil } + deltaCommitVersionWireValue, err := int64ToWire(v.DeltaCommitVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DeltaTableSyncInfo.DeltaCommitVersion", err) + } return &deltaTableSyncInfoWire{ - DeltaCommitVersion: v.DeltaCommitVersion, + DeltaCommitVersion: deltaCommitVersionWireValue, DeltaCommitTimestamp: v.DeltaCommitTimestamp, }, nil } @@ -521,8 +571,12 @@ func deltaTableSyncInfoFromWire(w *deltaTableSyncInfoWire) (*DeltaTableSyncInfo, if w == nil { return nil, nil } + deltaCommitVersionPublicValue, err := int64FromWire(w.DeltaCommitVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DeltaTableSyncInfo.DeltaCommitVersion", err) + } return &DeltaTableSyncInfo{ - DeltaCommitVersion: w.DeltaCommitVersion, + DeltaCommitVersion: deltaCommitVersionPublicValue, DeltaCommitTimestamp: w.DeltaCommitTimestamp, }, nil } @@ -840,7 +894,7 @@ func syncedDatabaseTableFromWire(w *syncedDatabaseTableWire) (*SyncedDatabaseTab } type syncedTableContinuousUpdateStatusWire struct { - LastProcessedCommitVersion *int64 `json:"last_processed_commit_version,omitempty"` + LastProcessedCommitVersion *wireInt64 `json:"last_processed_commit_version,omitempty"` Timestamp *types.Time `json:"timestamp,omitempty"` InitialPipelineSyncProgress *syncedTablePipelineProgressWire `json:"initial_pipeline_sync_progress,omitempty"` } @@ -849,12 +903,16 @@ func syncedTableContinuousUpdateStatusToWire(v *SyncedTableContinuousUpdateStatu if v == nil { return nil, nil } + lastProcessedCommitVersionWireValue, err := int64ToWire(v.LastProcessedCommitVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTableContinuousUpdateStatus.LastProcessedCommitVersion", err) + } initialPipelineSyncProgressWireValue, err := syncedTablePipelineProgressToWire(v.InitialPipelineSyncProgress) if err != nil { return nil, fmt.Errorf("%s: %w", "SyncedTableContinuousUpdateStatus.InitialPipelineSyncProgress", err) } return &syncedTableContinuousUpdateStatusWire{ - LastProcessedCommitVersion: v.LastProcessedCommitVersion, + LastProcessedCommitVersion: lastProcessedCommitVersionWireValue, Timestamp: v.Timestamp, InitialPipelineSyncProgress: initialPipelineSyncProgressWireValue, }, nil @@ -864,19 +922,23 @@ func syncedTableContinuousUpdateStatusFromWire(w *syncedTableContinuousUpdateSta if w == nil { return nil, nil } + lastProcessedCommitVersionPublicValue, err := int64FromWire(w.LastProcessedCommitVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTableContinuousUpdateStatus.LastProcessedCommitVersion", err) + } initialPipelineSyncProgressPublicValue, err := syncedTablePipelineProgressFromWire(w.InitialPipelineSyncProgress) if err != nil { return nil, fmt.Errorf("%s: %w", "SyncedTableContinuousUpdateStatus.InitialPipelineSyncProgress", err) } return &SyncedTableContinuousUpdateStatus{ - LastProcessedCommitVersion: w.LastProcessedCommitVersion, + LastProcessedCommitVersion: lastProcessedCommitVersionPublicValue, Timestamp: w.Timestamp, InitialPipelineSyncProgress: initialPipelineSyncProgressPublicValue, }, nil } type syncedTableFailedStatusWire struct { - LastProcessedCommitVersion *int64 `json:"last_processed_commit_version,omitempty"` + LastProcessedCommitVersion *wireInt64 `json:"last_processed_commit_version,omitempty"` Timestamp *types.Time `json:"timestamp,omitempty"` } @@ -884,8 +946,12 @@ func syncedTableFailedStatusToWire(v *SyncedTableFailedStatus) (*syncedTableFail if v == nil { return nil, nil } + lastProcessedCommitVersionWireValue, err := int64ToWire(v.LastProcessedCommitVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTableFailedStatus.LastProcessedCommitVersion", err) + } return &syncedTableFailedStatusWire{ - LastProcessedCommitVersion: v.LastProcessedCommitVersion, + LastProcessedCommitVersion: lastProcessedCommitVersionWireValue, Timestamp: v.Timestamp, }, nil } @@ -894,16 +960,20 @@ func syncedTableFailedStatusFromWire(w *syncedTableFailedStatusWire) (*SyncedTab if w == nil { return nil, nil } + lastProcessedCommitVersionPublicValue, err := int64FromWire(w.LastProcessedCommitVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTableFailedStatus.LastProcessedCommitVersion", err) + } return &SyncedTableFailedStatus{ - LastProcessedCommitVersion: w.LastProcessedCommitVersion, + LastProcessedCommitVersion: lastProcessedCommitVersionPublicValue, Timestamp: w.Timestamp, }, nil } type syncedTablePipelineProgressWire struct { - LatestVersionCurrentlyProcessing *int64 `json:"latest_version_currently_processing,omitempty"` - SyncedRowCount *int64 `json:"synced_row_count,omitempty"` - TotalRowCount *int64 `json:"total_row_count,omitempty"` + LatestVersionCurrentlyProcessing *wireInt64 `json:"latest_version_currently_processing,omitempty"` + SyncedRowCount *wireInt64 `json:"synced_row_count,omitempty"` + TotalRowCount *wireInt64 `json:"total_row_count,omitempty"` SyncProgressCompletion *float64 `json:"sync_progress_completion,omitempty"` EstimatedCompletionTimeSeconds *float64 `json:"estimated_completion_time_seconds,omitempty"` ProvisioningPhase ProvisioningPhase `json:"provisioning_phase,omitempty"` @@ -913,10 +983,22 @@ func syncedTablePipelineProgressToWire(v *SyncedTablePipelineProgress) (*syncedT if v == nil { return nil, nil } + latestVersionCurrentlyProcessingWireValue, err := int64ToWire(v.LatestVersionCurrentlyProcessing) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTablePipelineProgress.LatestVersionCurrentlyProcessing", err) + } + syncedRowCountWireValue, err := int64ToWire(v.SyncedRowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTablePipelineProgress.SyncedRowCount", err) + } + totalRowCountWireValue, err := int64ToWire(v.TotalRowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTablePipelineProgress.TotalRowCount", err) + } return &syncedTablePipelineProgressWire{ - LatestVersionCurrentlyProcessing: v.LatestVersionCurrentlyProcessing, - SyncedRowCount: v.SyncedRowCount, - TotalRowCount: v.TotalRowCount, + LatestVersionCurrentlyProcessing: latestVersionCurrentlyProcessingWireValue, + SyncedRowCount: syncedRowCountWireValue, + TotalRowCount: totalRowCountWireValue, SyncProgressCompletion: v.SyncProgressCompletion, EstimatedCompletionTimeSeconds: v.EstimatedCompletionTimeSeconds, ProvisioningPhase: v.ProvisioningPhase, @@ -927,10 +1009,22 @@ func syncedTablePipelineProgressFromWire(w *syncedTablePipelineProgressWire) (*S if w == nil { return nil, nil } + latestVersionCurrentlyProcessingPublicValue, err := int64FromWire(w.LatestVersionCurrentlyProcessing) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTablePipelineProgress.LatestVersionCurrentlyProcessing", err) + } + syncedRowCountPublicValue, err := int64FromWire(w.SyncedRowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTablePipelineProgress.SyncedRowCount", err) + } + totalRowCountPublicValue, err := int64FromWire(w.TotalRowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTablePipelineProgress.TotalRowCount", err) + } return &SyncedTablePipelineProgress{ - LatestVersionCurrentlyProcessing: w.LatestVersionCurrentlyProcessing, - SyncedRowCount: w.SyncedRowCount, - TotalRowCount: w.TotalRowCount, + LatestVersionCurrentlyProcessing: latestVersionCurrentlyProcessingPublicValue, + SyncedRowCount: syncedRowCountPublicValue, + TotalRowCount: totalRowCountPublicValue, SyncProgressCompletion: w.SyncProgressCompletion, EstimatedCompletionTimeSeconds: w.EstimatedCompletionTimeSeconds, ProvisioningPhase: w.ProvisioningPhase, @@ -1248,7 +1342,7 @@ func syncedTableStatusFromWire(w *syncedTableStatusWire) (*SyncedTableStatus, er } type syncedTableTriggeredUpdateStatusWire struct { - LastProcessedCommitVersion *int64 `json:"last_processed_commit_version,omitempty"` + LastProcessedCommitVersion *wireInt64 `json:"last_processed_commit_version,omitempty"` Timestamp *types.Time `json:"timestamp,omitempty"` TriggeredUpdateProgress *syncedTablePipelineProgressWire `json:"triggered_update_progress,omitempty"` } @@ -1257,12 +1351,16 @@ func syncedTableTriggeredUpdateStatusToWire(v *SyncedTableTriggeredUpdateStatus) if v == nil { return nil, nil } + lastProcessedCommitVersionWireValue, err := int64ToWire(v.LastProcessedCommitVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTableTriggeredUpdateStatus.LastProcessedCommitVersion", err) + } triggeredUpdateProgressWireValue, err := syncedTablePipelineProgressToWire(v.TriggeredUpdateProgress) if err != nil { return nil, fmt.Errorf("%s: %w", "SyncedTableTriggeredUpdateStatus.TriggeredUpdateProgress", err) } return &syncedTableTriggeredUpdateStatusWire{ - LastProcessedCommitVersion: v.LastProcessedCommitVersion, + LastProcessedCommitVersion: lastProcessedCommitVersionWireValue, Timestamp: v.Timestamp, TriggeredUpdateProgress: triggeredUpdateProgressWireValue, }, nil @@ -1272,12 +1370,16 @@ func syncedTableTriggeredUpdateStatusFromWire(w *syncedTableTriggeredUpdateStatu if w == nil { return nil, nil } + lastProcessedCommitVersionPublicValue, err := int64FromWire(w.LastProcessedCommitVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTableTriggeredUpdateStatus.LastProcessedCommitVersion", err) + } triggeredUpdateProgressPublicValue, err := syncedTablePipelineProgressFromWire(w.TriggeredUpdateProgress) if err != nil { return nil, fmt.Errorf("%s: %w", "SyncedTableTriggeredUpdateStatus.TriggeredUpdateProgress", err) } return &SyncedTableTriggeredUpdateStatus{ - LastProcessedCommitVersion: w.LastProcessedCommitVersion, + LastProcessedCommitVersion: lastProcessedCommitVersionPublicValue, Timestamp: w.Timestamp, TriggeredUpdateProgress: triggeredUpdateProgressPublicValue, }, nil diff --git a/dataclassification/CHANGELOG.md b/dataclassification/CHANGELOG.md index 6224c04..19f237c 100644 --- a/dataclassification/CHANGELOG.md +++ b/dataclassification/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/dataclassification/go.mod b/dataclassification/go.mod index 80c896b..afffa95 100644 --- a/dataclassification/go.mod +++ b/dataclassification/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/dataclassification/internal/version.go b/dataclassification/internal/version.go index 4ba2755..a112e17 100644 --- a/dataclassification/internal/version.go +++ b/dataclassification/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-dataclassification" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/dataclassification/v1/client.go b/dataclassification/v1/client.go old mode 100755 new mode 100644 index 7695338..b404ce5 --- a/dataclassification/v1/client.go +++ b/dataclassification/v1/client.go @@ -77,8 +77,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // // Creates a new config resource, which enables Data Classification for the // specified catalog. - The config must not already exist for the catalog. -func (c *internalClient) CreateCatalogConfig(ctx context.Context, req *CreateCatalogConfigRequest, opts ...call.Option) (*CatalogConfig, error) { - wireReq, err := createCatalogConfigRequestToWire(req) +func (c *internalClient) CreateCatalogConfig(ctx context.Context, req CreateCatalogConfigRequest, opts ...call.Option) (*CatalogConfig, error) { + wireReq, err := createCatalogConfigRequestToWire(&req) if err != nil { return nil, err } @@ -99,7 +99,11 @@ func (c *internalClient) CreateCatalogConfig(ctx context.Context, req *CreateCat } pb := pathBuilder{} pb.literal("/api/data-classification/v1/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/config") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -147,7 +151,7 @@ func (c *internalClient) CreateCatalogConfig(ctx context.Context, req *CreateCat } // Delete Data Classification configuration for a catalog. -func (c *internalClient) DeleteCatalogConfig(ctx context.Context, req *DeleteCatalogConfigRequest, opts ...call.Option) error { +func (c *internalClient) DeleteCatalogConfig(ctx context.Context, req DeleteCatalogConfigRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -161,7 +165,11 @@ func (c *internalClient) DeleteCatalogConfig(ctx context.Context, req *DeleteCat } pb := pathBuilder{} pb.literal("/api/data-classification/v1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -198,7 +206,7 @@ func (c *internalClient) DeleteCatalogConfig(ctx context.Context, req *DeleteCat } // Get the Data Classification configuration for a catalog. -func (c *internalClient) GetCatalogConfig(ctx context.Context, req *GetCatalogConfigRequest, opts ...call.Option) (*CatalogConfig, error) { +func (c *internalClient) GetCatalogConfig(ctx context.Context, req GetCatalogConfigRequest, opts ...call.Option) (*CatalogConfig, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -212,7 +220,11 @@ func (c *internalClient) GetCatalogConfig(ctx context.Context, req *GetCatalogCo } pb := pathBuilder{} pb.literal("/api/data-classification/v1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -260,8 +272,8 @@ func (c *internalClient) GetCatalogConfig(ctx context.Context, req *GetCatalogCo // Update the Data Classification configuration for a catalog. - The config must // already exist for the catalog. - Updates fields specified in the update_mask. // Use update_mask field to perform partial updates of the configuration. -func (c *internalClient) UpdateCatalogConfig(ctx context.Context, req *UpdateCatalogConfigRequest, opts ...call.Option) (*CatalogConfig, error) { - wireReq, err := updateCatalogConfigRequestToWire(req) +func (c *internalClient) UpdateCatalogConfig(ctx context.Context, req UpdateCatalogConfigRequest, opts ...call.Option) (*CatalogConfig, error) { + wireReq, err := updateCatalogConfigRequestToWire(&req) if err != nil { return nil, err } @@ -282,7 +294,11 @@ func (c *internalClient) UpdateCatalogConfig(ctx context.Context, req *UpdateCat } pb := pathBuilder{} pb.literal("/api/data-classification/v1/") - pb.singleSegment(*req.CatalogConfig.Name) + if req.CatalogConfig == nil || req.CatalogConfig.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CatalogConfig.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { diff --git a/dataclassification/v1/genhelper.go b/dataclassification/v1/genhelper.go old mode 100755 new mode 100644 index 6f31f26..b30d068 --- a/dataclassification/v1/genhelper.go +++ b/dataclassification/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/dataquality/CHANGELOG.md b/dataquality/CHANGELOG.md index 6224c04..19f237c 100644 --- a/dataquality/CHANGELOG.md +++ b/dataquality/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/dataquality/go.mod b/dataquality/go.mod index 2f2a640..cbfc8d0 100644 --- a/dataquality/go.mod +++ b/dataquality/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/dataquality/internal/version.go b/dataquality/internal/version.go index 3db83fc..d92e314 100644 --- a/dataquality/internal/version.go +++ b/dataquality/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-dataquality" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/dataquality/v1/client.go b/dataquality/v1/client.go old mode 100755 new mode 100644 index 28c5b51..eb91d71 --- a/dataquality/v1/client.go +++ b/dataquality/v1/client.go @@ -84,8 +84,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // **USE_SCHEMA** on the table's parent schema. 3. **USE_CATALOG** on the // table's parent catalog, **USE_SCHEMA** on the table's parent schema, and // **MANAGE** on the table. -func (c *internalClient) CancelRefresh(ctx context.Context, req *CancelRefreshRequest, opts ...call.Option) (*CancelRefreshResponse, error) { - wireReq, err := cancelRefreshRequestToWire(req) +func (c *internalClient) CancelRefresh(ctx context.Context, req CancelRefreshRequest, opts ...call.Option) (*CancelRefreshResponse, error) { + wireReq, err := cancelRefreshRequestToWire(&req) if err != nil { return nil, err } @@ -106,11 +106,23 @@ func (c *internalClient) CancelRefresh(ctx context.Context, req *CancelRefreshRe } pb := pathBuilder{} pb.literal("/api/data-quality/v1/monitors/") - pb.singleSegment(*req.ObjectType) + if req.ObjectType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ObjectType) + } pb.literal("/") - pb.singleSegment(*req.ObjectId) + if req.ObjectId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ObjectId) + } pb.literal("/refreshes/") - pb.singleSegment(*req.RefreshId) + if req.RefreshId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.RefreshId) + } pb.literal("/cancel") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -176,8 +188,8 @@ func (c *internalClient) CancelRefresh(ctx context.Context, req *CancelRefreshRe // sets of permissions: 1. **MANAGE** and **USE_CATALOG** on the schema's parent // catalog. 2. **USE_CATALOG** on the schema's parent catalog, and **MANAGE** // and **USE_SCHEMA** on the schema. -func (c *internalClient) CreateMonitor(ctx context.Context, req *CreateMonitorRequest, opts ...call.Option) (*Monitor, error) { - wireReq, err := createMonitorRequestToWire(req) +func (c *internalClient) CreateMonitor(ctx context.Context, req CreateMonitorRequest, opts ...call.Option) (*Monitor, error) { + wireReq, err := createMonitorRequestToWire(&req) if err != nil { return nil, err } @@ -250,8 +262,8 @@ func (c *internalClient) CreateMonitor(ctx context.Context, req *CreateMonitorRe // **USE_SCHEMA** on the table's parent schema. 3. **USE_CATALOG** on the // table's parent catalog, **USE_SCHEMA** on the table's parent schema, and // **MANAGE** on the table. -func (c *internalClient) CreateRefresh(ctx context.Context, req *CreateRefreshRequest, opts ...call.Option) (*Refresh, error) { - wireReq, err := createRefreshRequestToWire(req) +func (c *internalClient) CreateRefresh(ctx context.Context, req CreateRefreshRequest, opts ...call.Option) (*Refresh, error) { + wireReq, err := createRefreshRequestToWire(&req) if err != nil { return nil, err } @@ -272,9 +284,17 @@ func (c *internalClient) CreateRefresh(ctx context.Context, req *CreateRefreshRe } pb := pathBuilder{} pb.literal("/api/data-quality/v1/monitors/") - pb.singleSegment(*req.Refresh.ObjectType) + if req.Refresh == nil || req.Refresh.ObjectType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Refresh.ObjectType) + } pb.literal("/") - pb.singleSegment(*req.Refresh.ObjectId) + if req.Refresh == nil || req.Refresh.ObjectId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Refresh.ObjectId) + } pb.literal("/refreshes") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -337,7 +357,7 @@ func (c *internalClient) CreateRefresh(ctx context.Context, req *CreateRefreshRe // sets of permissions: 1. **MANAGE** and **USE_CATALOG** on the schema's parent // catalog. 2. **USE_CATALOG** on the schema's parent catalog, and **MANAGE** // and **USE_SCHEMA** on the schema. -func (c *internalClient) DeleteMonitor(ctx context.Context, req *DeleteMonitorRequest, opts ...call.Option) error { +func (c *internalClient) DeleteMonitor(ctx context.Context, req DeleteMonitorRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -351,9 +371,17 @@ func (c *internalClient) DeleteMonitor(ctx context.Context, req *DeleteMonitorRe } pb := pathBuilder{} pb.literal("/api/data-quality/v1/monitors/") - pb.singleSegment(*req.ObjectType) + if req.ObjectType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ObjectType) + } pb.literal("/") - pb.singleSegment(*req.ObjectId) + if req.ObjectId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ObjectId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -390,7 +418,7 @@ func (c *internalClient) DeleteMonitor(ctx context.Context, req *DeleteMonitorRe } // (Unimplemented) Delete a refresh -func (c *internalClient) DeleteRefresh(ctx context.Context, req *DeleteRefreshRequest, opts ...call.Option) error { +func (c *internalClient) DeleteRefresh(ctx context.Context, req DeleteRefreshRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -404,11 +432,23 @@ func (c *internalClient) DeleteRefresh(ctx context.Context, req *DeleteRefreshRe } pb := pathBuilder{} pb.literal("/api/data-quality/v1/monitors/") - pb.singleSegment(*req.ObjectType) + if req.ObjectType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ObjectType) + } pb.literal("/") - pb.singleSegment(*req.ObjectId) + if req.ObjectId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ObjectId) + } pb.literal("/refreshes/") - pb.singleSegment(*req.RefreshId) + if req.RefreshId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.RefreshId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -462,7 +502,7 @@ func (c *internalClient) DeleteRefresh(ctx context.Context, req *DeleteRefreshRe // parent entity as well as information on assets created by the monitor. Some // information (e.g. dashboard) may be filtered out if the caller is in a // different workspace than where the monitor was created. -func (c *internalClient) GetMonitor(ctx context.Context, req *GetMonitorRequest, opts ...call.Option) (*Monitor, error) { +func (c *internalClient) GetMonitor(ctx context.Context, req GetMonitorRequest, opts ...call.Option) (*Monitor, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -476,9 +516,17 @@ func (c *internalClient) GetMonitor(ctx context.Context, req *GetMonitorRequest, } pb := pathBuilder{} pb.literal("/api/data-quality/v1/monitors/") - pb.singleSegment(*req.ObjectType) + if req.ObjectType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ObjectType) + } pb.literal("/") - pb.singleSegment(*req.ObjectId) + if req.ObjectId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ObjectId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -537,7 +585,7 @@ func (c *internalClient) GetMonitor(ctx context.Context, req *GetMonitorRequest, // sets of permissions: 1. **MANAGE** and **USE_CATALOG** on the schema's parent // catalog. 2. **USE_CATALOG** on the schema's parent catalog, and // **USE_SCHEMA** on the schema. -func (c *internalClient) GetRefresh(ctx context.Context, req *GetRefreshRequest, opts ...call.Option) (*Refresh, error) { +func (c *internalClient) GetRefresh(ctx context.Context, req GetRefreshRequest, opts ...call.Option) (*Refresh, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -551,11 +599,23 @@ func (c *internalClient) GetRefresh(ctx context.Context, req *GetRefreshRequest, } pb := pathBuilder{} pb.literal("/api/data-quality/v1/monitors/") - pb.singleSegment(*req.ObjectType) + if req.ObjectType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ObjectType) + } pb.literal("/") - pb.singleSegment(*req.ObjectId) + if req.ObjectId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ObjectId) + } pb.literal("/refreshes/") - pb.singleSegment(*req.RefreshId) + if req.RefreshId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.RefreshId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -601,8 +661,8 @@ func (c *internalClient) GetRefresh(ctx context.Context, req *GetRefreshRequest, } // (Unimplemented) List data quality monitors. -func (c *internalClient) ListMonitor(ctx context.Context, req *ListMonitorRequest, opts ...call.Option) (*ListMonitorResponse, error) { - wireReq, err := listMonitorRequestToWire(req) +func (c *internalClient) ListMonitor(ctx context.Context, req ListMonitorRequest, opts ...call.Option) (*ListMonitorResponse, error) { + wireReq, err := listMonitorRequestToWire(&req) if err != nil { return nil, err } @@ -672,7 +732,7 @@ func (c *internalClient) ListMonitor(ctx context.Context, req *ListMonitorReques // // For example: // -// for item, err := range c.ListMonitorIter(ctx, &ListMonitorRequest{}) { +// for item, err := range c.ListMonitorIter(ctx, ListMonitorRequest{}) { // if err != nil { // return err // } @@ -684,16 +744,13 @@ func (c *internalClient) ListMonitor(ctx context.Context, req *ListMonitorReques // // Callers who need custom pagination logic should use // ListMonitor directly. -func (c *internalClient) ListMonitorIter(ctx context.Context, req *ListMonitorRequest, opts ...call.Option) iter.Seq2[*Monitor, error] { +func (c *internalClient) ListMonitorIter(ctx context.Context, req ListMonitorRequest, opts ...call.Option) iter.Seq2[*Monitor, error] { return func(yield func(*Monitor, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListMonitorRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListMonitor(ctx, &pageReq, opts...) + resp, err := c.ListMonitor(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -725,8 +782,8 @@ func (c *internalClient) ListMonitorIter(ctx context.Context, req *ListMonitorRe // sets of permissions: 1. **MANAGE** and **USE_CATALOG** on the schema's parent // catalog. 2. **USE_CATALOG** on the schema's parent catalog, and // **USE_SCHEMA** on the schema. -func (c *internalClient) ListRefresh(ctx context.Context, req *ListRefreshRequest, opts ...call.Option) (*ListRefreshResponse, error) { - wireReq, err := listRefreshRequestToWire(req) +func (c *internalClient) ListRefresh(ctx context.Context, req ListRefreshRequest, opts ...call.Option) (*ListRefreshResponse, error) { + wireReq, err := listRefreshRequestToWire(&req) if err != nil { return nil, err } @@ -743,9 +800,17 @@ func (c *internalClient) ListRefresh(ctx context.Context, req *ListRefreshReques } pb := pathBuilder{} pb.literal("/api/data-quality/v1/monitors/") - pb.singleSegment(*req.ObjectType) + if req.ObjectType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ObjectType) + } pb.literal("/") - pb.singleSegment(*req.ObjectId) + if req.ObjectId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ObjectId) + } pb.literal("/refreshes") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -802,7 +867,7 @@ func (c *internalClient) ListRefresh(ctx context.Context, req *ListRefreshReques // // For example: // -// for item, err := range c.ListRefreshIter(ctx, &ListRefreshRequest{}) { +// for item, err := range c.ListRefreshIter(ctx, ListRefreshRequest{}) { // if err != nil { // return err // } @@ -814,16 +879,13 @@ func (c *internalClient) ListRefresh(ctx context.Context, req *ListRefreshReques // // Callers who need custom pagination logic should use // ListRefresh directly. -func (c *internalClient) ListRefreshIter(ctx context.Context, req *ListRefreshRequest, opts ...call.Option) iter.Seq2[*Refresh, error] { +func (c *internalClient) ListRefreshIter(ctx context.Context, req ListRefreshRequest, opts ...call.Option) iter.Seq2[*Refresh, error] { return func(yield func(*Refresh, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListRefreshRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListRefresh(ctx, &pageReq, opts...) + resp, err := c.ListRefresh(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -854,8 +916,8 @@ func (c *internalClient) ListRefreshIter(ctx context.Context, req *ListRefreshRe // sets of permissions: 1. **MANAGE** and **USE_CATALOG** on the schema's parent // catalog. 2. **USE_CATALOG** on the schema's parent catalog, and **MANAGE** // and **USE_SCHEMA** on the schema. -func (c *internalClient) UpdateMonitor(ctx context.Context, req *UpdateMonitorRequest, opts ...call.Option) (*Monitor, error) { - wireReq, err := updateMonitorRequestToWire(req) +func (c *internalClient) UpdateMonitor(ctx context.Context, req UpdateMonitorRequest, opts ...call.Option) (*Monitor, error) { + wireReq, err := updateMonitorRequestToWire(&req) if err != nil { return nil, err } @@ -876,9 +938,17 @@ func (c *internalClient) UpdateMonitor(ctx context.Context, req *UpdateMonitorRe } pb := pathBuilder{} pb.literal("/api/data-quality/v1/monitors/") - pb.singleSegment(*req.ObjectType) + if req.ObjectType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ObjectType) + } pb.literal("/") - pb.singleSegment(*req.ObjectId) + if req.ObjectId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ObjectId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -928,8 +998,8 @@ func (c *internalClient) UpdateMonitor(ctx context.Context, req *UpdateMonitorRe } // (Unimplemented) Update a refresh -func (c *internalClient) UpdateRefresh(ctx context.Context, req *UpdateRefreshRequest, opts ...call.Option) (*Refresh, error) { - wireReq, err := updateRefreshRequestToWire(req) +func (c *internalClient) UpdateRefresh(ctx context.Context, req UpdateRefreshRequest, opts ...call.Option) (*Refresh, error) { + wireReq, err := updateRefreshRequestToWire(&req) if err != nil { return nil, err } @@ -950,11 +1020,23 @@ func (c *internalClient) UpdateRefresh(ctx context.Context, req *UpdateRefreshRe } pb := pathBuilder{} pb.literal("/api/data-quality/v1/monitors/") - pb.singleSegment(*req.ObjectType) + if req.ObjectType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ObjectType) + } pb.literal("/") - pb.singleSegment(*req.ObjectId) + if req.ObjectId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ObjectId) + } pb.literal("/refreshes/") - pb.singleSegment(*req.RefreshId) + if req.RefreshId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.RefreshId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { diff --git a/dataquality/v1/genhelper.go b/dataquality/v1/genhelper.go old mode 100755 new mode 100644 index 25e969e..14ed8f6 --- a/dataquality/v1/genhelper.go +++ b/dataquality/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/dataquality/v1/wire.go b/dataquality/v1/wire.go old mode 100755 new mode 100644 index 8d739ab..7cbaf99 --- a/dataquality/v1/wire.go +++ b/dataquality/v1/wire.go @@ -3,11 +3,57 @@ package dataquality import ( + "bytes" + "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + func fieldMaskToWire[T any](mask *types.FieldMask[T]) *string { if mask == nil { return nil @@ -39,19 +85,23 @@ func anomalyDetectionConfigFromWire(w *anomalyDetectionConfigWire) (*AnomalyDete } type cancelRefreshRequestWire struct { - ObjectType *string `json:"object_type,omitempty"` - ObjectId *string `json:"object_id,omitempty"` - RefreshId *int64 `json:"refresh_id,omitempty"` + ObjectType *string `json:"object_type,omitempty"` + ObjectId *string `json:"object_id,omitempty"` + RefreshId *wireInt64 `json:"refresh_id,omitempty"` } func cancelRefreshRequestToWire(v *CancelRefreshRequest) (*cancelRefreshRequestWire, error) { if v == nil { return nil, nil } + refreshIdWireValue, err := int64ToWire(v.RefreshId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CancelRefreshRequest.RefreshId", err) + } return &cancelRefreshRequestWire{ ObjectType: v.ObjectType, ObjectId: v.ObjectId, - RefreshId: v.RefreshId, + RefreshId: refreshIdWireValue, }, nil } @@ -153,7 +203,7 @@ type dataProfilingConfigWire struct { ProfileMetricsTableName *string `json:"profile_metrics_table_name,omitempty"` DriftMetricsTableName *string `json:"drift_metrics_table_name,omitempty"` DashboardId *string `json:"dashboard_id,omitempty"` - MonitorVersion *int64 `json:"monitor_version,omitempty"` + MonitorVersion *wireInt64 `json:"monitor_version,omitempty"` EffectiveWarehouseId *string `json:"effective_warehouse_id,omitempty"` } @@ -173,6 +223,10 @@ func dataProfilingConfigToWire(v *DataProfilingConfig) (*dataProfilingConfigWire if err != nil { return nil, fmt.Errorf("%s: %w", "DataProfilingConfig.NotificationSettings", err) } + monitorVersionWireValue, err := int64ToWire(v.MonitorVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DataProfilingConfig.MonitorVersion", err) + } var analysisConfigInferenceLogWire *inferenceLogConfigWire var analysisConfigTimeSeriesWire *timeSeriesConfigWire var analysisConfigSnapshotWire *snapshotConfigWire @@ -224,7 +278,7 @@ func dataProfilingConfigToWire(v *DataProfilingConfig) (*dataProfilingConfigWire ProfileMetricsTableName: v.ProfileMetricsTableName, DriftMetricsTableName: v.DriftMetricsTableName, DashboardId: v.DashboardId, - MonitorVersion: v.MonitorVersion, + MonitorVersion: monitorVersionWireValue, EffectiveWarehouseId: v.EffectiveWarehouseId, }, nil } @@ -258,6 +312,10 @@ func dataProfilingConfigFromWire(w *dataProfilingConfigWire) (*DataProfilingConf if err != nil { return nil, fmt.Errorf("%s: %w", "DataProfilingConfig.NotificationSettings", err) } + monitorVersionPublicValue, err := int64FromWire(w.MonitorVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DataProfilingConfig.MonitorVersion", err) + } var analysisConfigSelection isDataProfilingConfig_AnalysisConfig switch { case w.InferenceLog != nil: @@ -295,7 +353,7 @@ func dataProfilingConfigFromWire(w *dataProfilingConfigWire) (*DataProfilingConf ProfileMetricsTableName: w.ProfileMetricsTableName, DriftMetricsTableName: w.DriftMetricsTableName, DashboardId: w.DashboardId, - MonitorVersion: w.MonitorVersion, + MonitorVersion: monitorVersionPublicValue, EffectiveWarehouseId: w.EffectiveWarehouseId, AnalysisConfig: analysisConfigSelection, }, nil @@ -546,11 +604,11 @@ func notificationSettingsFromWire(w *notificationSettingsWire) (*NotificationSet type refreshWire struct { ObjectType *string `json:"object_type,omitempty"` ObjectId *string `json:"object_id,omitempty"` - RefreshId *int64 `json:"refresh_id,omitempty"` + RefreshId *wireInt64 `json:"refresh_id,omitempty"` State RefreshState `json:"state,omitempty"` Message *string `json:"message,omitempty"` - StartTimeMs *int64 `json:"start_time_ms,omitempty"` - EndTimeMs *int64 `json:"end_time_ms,omitempty"` + StartTimeMs *wireInt64 `json:"start_time_ms,omitempty"` + EndTimeMs *wireInt64 `json:"end_time_ms,omitempty"` Trigger RefreshTrigger `json:"trigger,omitempty"` } @@ -558,14 +616,26 @@ func refreshToWire(v *Refresh) (*refreshWire, error) { if v == nil { return nil, nil } + refreshIdWireValue, err := int64ToWire(v.RefreshId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Refresh.RefreshId", err) + } + startTimeMsWireValue, err := int64ToWire(v.StartTimeMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Refresh.StartTimeMs", err) + } + endTimeMsWireValue, err := int64ToWire(v.EndTimeMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Refresh.EndTimeMs", err) + } return &refreshWire{ ObjectType: v.ObjectType, ObjectId: v.ObjectId, - RefreshId: v.RefreshId, + RefreshId: refreshIdWireValue, State: v.State, Message: v.Message, - StartTimeMs: v.StartTimeMs, - EndTimeMs: v.EndTimeMs, + StartTimeMs: startTimeMsWireValue, + EndTimeMs: endTimeMsWireValue, Trigger: v.Trigger, }, nil } @@ -574,14 +644,26 @@ func refreshFromWire(w *refreshWire) (*Refresh, error) { if w == nil { return nil, nil } + refreshIdPublicValue, err := int64FromWire(w.RefreshId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Refresh.RefreshId", err) + } + startTimeMsPublicValue, err := int64FromWire(w.StartTimeMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Refresh.StartTimeMs", err) + } + endTimeMsPublicValue, err := int64FromWire(w.EndTimeMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Refresh.EndTimeMs", err) + } return &Refresh{ ObjectType: w.ObjectType, ObjectId: w.ObjectId, - RefreshId: w.RefreshId, + RefreshId: refreshIdPublicValue, State: w.State, Message: w.Message, - StartTimeMs: w.StartTimeMs, - EndTimeMs: w.EndTimeMs, + StartTimeMs: startTimeMsPublicValue, + EndTimeMs: endTimeMsPublicValue, Trigger: w.Trigger, }, nil } @@ -654,7 +736,7 @@ func updateMonitorRequestToWire(v *UpdateMonitorRequest) (*updateMonitorRequestW type updateRefreshRequestWire struct { ObjectType *string `json:"object_type,omitempty"` ObjectId *string `json:"object_id,omitempty"` - RefreshId *int64 `json:"refresh_id,omitempty"` + RefreshId *wireInt64 `json:"refresh_id,omitempty"` Refresh *refreshWire `json:"refresh,omitempty"` UpdateMask *string `json:"update_mask,omitempty"` } @@ -663,6 +745,10 @@ func updateRefreshRequestToWire(v *UpdateRefreshRequest) (*updateRefreshRequestW if v == nil { return nil, nil } + refreshIdWireValue, err := int64ToWire(v.RefreshId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateRefreshRequest.RefreshId", err) + } refreshWireValue, err := refreshToWire(v.Refresh) if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateRefreshRequest.Refresh", err) @@ -670,7 +756,7 @@ func updateRefreshRequestToWire(v *UpdateRefreshRequest) (*updateRefreshRequestW return &updateRefreshRequestWire{ ObjectType: v.ObjectType, ObjectId: v.ObjectId, - RefreshId: v.RefreshId, + RefreshId: refreshIdWireValue, Refresh: refreshWireValue, UpdateMask: fieldMaskToWire(v.UpdateMask), }, nil diff --git a/disasterrecovery/CHANGELOG.md b/disasterrecovery/CHANGELOG.md index 6224c04..19f237c 100644 --- a/disasterrecovery/CHANGELOG.md +++ b/disasterrecovery/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/disasterrecovery/go.mod b/disasterrecovery/go.mod index 16f5194..5eb1441 100644 --- a/disasterrecovery/go.mod +++ b/disasterrecovery/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/disasterrecovery/internal/version.go b/disasterrecovery/internal/version.go index 06968b9..6bf2bad 100644 --- a/disasterrecovery/internal/version.go +++ b/disasterrecovery/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-disasterrecovery" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/disasterrecovery/v1/client.go b/disasterrecovery/v1/client.go old mode 100755 new mode 100644 index 44c13e8..622fa8a --- a/disasterrecovery/v1/client.go +++ b/disasterrecovery/v1/client.go @@ -75,8 +75,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Create a new failover group. -func (c *internalClient) CreateFailoverGroup(ctx context.Context, req *CreateFailoverGroupRequest, opts ...call.Option) (*FailoverGroup, error) { - wireReq, err := createFailoverGroupRequestToWire(req) +func (c *internalClient) CreateFailoverGroup(ctx context.Context, req CreateFailoverGroupRequest, opts ...call.Option) (*FailoverGroup, error) { + wireReq, err := createFailoverGroupRequestToWire(&req) if err != nil { return nil, err } @@ -97,7 +97,11 @@ func (c *internalClient) CreateFailoverGroup(ctx context.Context, req *CreateFai } pb := pathBuilder{} pb.literal("/api/disaster-recovery/v1/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/failover-groups") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -151,8 +155,8 @@ func (c *internalClient) CreateFailoverGroup(ctx context.Context, req *CreateFai } // Create a new stable URL. -func (c *internalClient) CreateStableUrl(ctx context.Context, req *CreateStableUrlRequest, opts ...call.Option) (*StableUrl, error) { - wireReq, err := createStableUrlRequestToWire(req) +func (c *internalClient) CreateStableUrl(ctx context.Context, req CreateStableUrlRequest, opts ...call.Option) (*StableUrl, error) { + wireReq, err := createStableUrlRequestToWire(&req) if err != nil { return nil, err } @@ -173,7 +177,11 @@ func (c *internalClient) CreateStableUrl(ctx context.Context, req *CreateStableU } pb := pathBuilder{} pb.literal("/api/disaster-recovery/v1/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/stable-urls") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -227,8 +235,8 @@ func (c *internalClient) CreateStableUrl(ctx context.Context, req *CreateStableU } // Delete a failover group. -func (c *internalClient) DeleteFailoverGroup(ctx context.Context, req *DeleteFailoverGroupRequest, opts ...call.Option) error { - wireReq, err := deleteFailoverGroupRequestToWire(req) +func (c *internalClient) DeleteFailoverGroup(ctx context.Context, req DeleteFailoverGroupRequest, opts ...call.Option) error { + wireReq, err := deleteFailoverGroupRequestToWire(&req) if err != nil { return err } @@ -245,7 +253,11 @@ func (c *internalClient) DeleteFailoverGroup(ctx context.Context, req *DeleteFai } pb := pathBuilder{} pb.literal("/api/disaster-recovery/v1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "etag", wireReq.Etag); err != nil { @@ -285,7 +297,7 @@ func (c *internalClient) DeleteFailoverGroup(ctx context.Context, req *DeleteFai } // Delete a stable URL. -func (c *internalClient) DeleteStableUrl(ctx context.Context, req *DeleteStableUrlRequest, opts ...call.Option) error { +func (c *internalClient) DeleteStableUrl(ctx context.Context, req DeleteStableUrlRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -299,7 +311,11 @@ func (c *internalClient) DeleteStableUrl(ctx context.Context, req *DeleteStableU } pb := pathBuilder{} pb.literal("/api/disaster-recovery/v1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -336,8 +352,8 @@ func (c *internalClient) DeleteStableUrl(ctx context.Context, req *DeleteStableU } // Initiate a failover to a new primary region. -func (c *internalClient) FailoverFailoverGroup(ctx context.Context, req *FailoverFailoverGroupRequest, opts ...call.Option) (*FailoverGroup, error) { - wireReq, err := failoverFailoverGroupRequestToWire(req) +func (c *internalClient) FailoverFailoverGroup(ctx context.Context, req FailoverFailoverGroupRequest, opts ...call.Option) (*FailoverGroup, error) { + wireReq, err := failoverFailoverGroupRequestToWire(&req) if err != nil { return nil, err } @@ -358,7 +374,11 @@ func (c *internalClient) FailoverFailoverGroup(ctx context.Context, req *Failove } pb := pathBuilder{} pb.literal("/api/disaster-recovery/v1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/failover") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -406,7 +426,7 @@ func (c *internalClient) FailoverFailoverGroup(ctx context.Context, req *Failove } // Get a failover group. -func (c *internalClient) GetFailoverGroup(ctx context.Context, req *GetFailoverGroupRequest, opts ...call.Option) (*FailoverGroup, error) { +func (c *internalClient) GetFailoverGroup(ctx context.Context, req GetFailoverGroupRequest, opts ...call.Option) (*FailoverGroup, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -420,7 +440,11 @@ func (c *internalClient) GetFailoverGroup(ctx context.Context, req *GetFailoverG } pb := pathBuilder{} pb.literal("/api/disaster-recovery/v1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -466,7 +490,7 @@ func (c *internalClient) GetFailoverGroup(ctx context.Context, req *GetFailoverG } // Get a stable URL. -func (c *internalClient) GetStableUrl(ctx context.Context, req *GetStableUrlRequest, opts ...call.Option) (*StableUrl, error) { +func (c *internalClient) GetStableUrl(ctx context.Context, req GetStableUrlRequest, opts ...call.Option) (*StableUrl, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -480,7 +504,11 @@ func (c *internalClient) GetStableUrl(ctx context.Context, req *GetStableUrlRequ } pb := pathBuilder{} pb.literal("/api/disaster-recovery/v1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -529,8 +557,8 @@ func (c *internalClient) GetStableUrl(ctx context.Context, req *GetStableUrlRequ // // List entries are abbreviated: `state` and `replication_point` are not // populated. Call GetFailoverGroup to retrieve the full resource. -func (c *internalClient) ListFailoverGroups(ctx context.Context, req *ListFailoverGroupsRequest, opts ...call.Option) (*ListFailoverGroupsResponse, error) { - wireReq, err := listFailoverGroupsRequestToWire(req) +func (c *internalClient) ListFailoverGroups(ctx context.Context, req ListFailoverGroupsRequest, opts ...call.Option) (*ListFailoverGroupsResponse, error) { + wireReq, err := listFailoverGroupsRequestToWire(&req) if err != nil { return nil, err } @@ -547,7 +575,11 @@ func (c *internalClient) ListFailoverGroups(ctx context.Context, req *ListFailov } pb := pathBuilder{} pb.literal("/api/disaster-recovery/v1/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/failover-groups") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -604,7 +636,7 @@ func (c *internalClient) ListFailoverGroups(ctx context.Context, req *ListFailov // // For example: // -// for item, err := range c.ListFailoverGroupsIter(ctx, &ListFailoverGroupsRequest{}) { +// for item, err := range c.ListFailoverGroupsIter(ctx, ListFailoverGroupsRequest{}) { // if err != nil { // return err // } @@ -616,16 +648,13 @@ func (c *internalClient) ListFailoverGroups(ctx context.Context, req *ListFailov // // Callers who need custom pagination logic should use // ListFailoverGroups directly. -func (c *internalClient) ListFailoverGroupsIter(ctx context.Context, req *ListFailoverGroupsRequest, opts ...call.Option) iter.Seq2[*FailoverGroup, error] { +func (c *internalClient) ListFailoverGroupsIter(ctx context.Context, req ListFailoverGroupsRequest, opts ...call.Option) iter.Seq2[*FailoverGroup, error] { return func(yield func(*FailoverGroup, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListFailoverGroupsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListFailoverGroups(ctx, &pageReq, opts...) + resp, err := c.ListFailoverGroups(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -644,8 +673,8 @@ func (c *internalClient) ListFailoverGroupsIter(ctx context.Context, req *ListFa } // List stable URLs for an account. -func (c *internalClient) ListStableUrls(ctx context.Context, req *ListStableUrlsRequest, opts ...call.Option) (*ListStableUrlsResponse, error) { - wireReq, err := listStableUrlsRequestToWire(req) +func (c *internalClient) ListStableUrls(ctx context.Context, req ListStableUrlsRequest, opts ...call.Option) (*ListStableUrlsResponse, error) { + wireReq, err := listStableUrlsRequestToWire(&req) if err != nil { return nil, err } @@ -662,7 +691,11 @@ func (c *internalClient) ListStableUrls(ctx context.Context, req *ListStableUrls } pb := pathBuilder{} pb.literal("/api/disaster-recovery/v1/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/stable-urls") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -719,7 +752,7 @@ func (c *internalClient) ListStableUrls(ctx context.Context, req *ListStableUrls // // For example: // -// for item, err := range c.ListStableUrlsIter(ctx, &ListStableUrlsRequest{}) { +// for item, err := range c.ListStableUrlsIter(ctx, ListStableUrlsRequest{}) { // if err != nil { // return err // } @@ -731,16 +764,13 @@ func (c *internalClient) ListStableUrls(ctx context.Context, req *ListStableUrls // // Callers who need custom pagination logic should use // ListStableUrls directly. -func (c *internalClient) ListStableUrlsIter(ctx context.Context, req *ListStableUrlsRequest, opts ...call.Option) iter.Seq2[*StableUrl, error] { +func (c *internalClient) ListStableUrlsIter(ctx context.Context, req ListStableUrlsRequest, opts ...call.Option) iter.Seq2[*StableUrl, error] { return func(yield func(*StableUrl, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListStableUrlsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListStableUrls(ctx, &pageReq, opts...) + resp, err := c.ListStableUrls(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -759,8 +789,8 @@ func (c *internalClient) ListStableUrlsIter(ctx context.Context, req *ListStable } // Update a failover group. -func (c *internalClient) UpdateFailoverGroup(ctx context.Context, req *UpdateFailoverGroupRequest, opts ...call.Option) (*FailoverGroup, error) { - wireReq, err := updateFailoverGroupRequestToWire(req) +func (c *internalClient) UpdateFailoverGroup(ctx context.Context, req UpdateFailoverGroupRequest, opts ...call.Option) (*FailoverGroup, error) { + wireReq, err := updateFailoverGroupRequestToWire(&req) if err != nil { return nil, err } @@ -781,7 +811,11 @@ func (c *internalClient) UpdateFailoverGroup(ctx context.Context, req *UpdateFai } pb := pathBuilder{} pb.literal("/api/disaster-recovery/v1/") - pb.singleSegment(*req.FailoverGroup.Name) + if req.FailoverGroup == nil || req.FailoverGroup.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FailoverGroup.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { diff --git a/disasterrecovery/v1/genhelper.go b/disasterrecovery/v1/genhelper.go old mode 100755 new mode 100644 index 7859a20..6acf04e --- a/disasterrecovery/v1/genhelper.go +++ b/disasterrecovery/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/environments/CHANGELOG.md b/environments/CHANGELOG.md index 6224c04..19f237c 100644 --- a/environments/CHANGELOG.md +++ b/environments/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/environments/go.mod b/environments/go.mod index b14ef4c..2c50636 100644 --- a/environments/go.mod +++ b/environments/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/environments/internal/version.go b/environments/internal/version.go index 3d73e05..ff591d3 100644 --- a/environments/internal/version.go +++ b/environments/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-environments" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/environments/v1/client.go b/environments/v1/client.go old mode 100755 new mode 100644 index f1d4f04..6ba7e6f --- a/environments/v1/client.go +++ b/environments/v1/client.go @@ -80,8 +80,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // operation will asynchronously generate a materialized environment to optimize // dependency resolution and is only marked as done when the materialized // environment has been successfully generated or has failed. -func (c *internalClient) createWorkspaceBaseEnvironmentBase(ctx context.Context, req *CreateWorkspaceBaseEnvironmentRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := createWorkspaceBaseEnvironmentRequestToWire(req) +func (c *internalClient) createWorkspaceBaseEnvironmentBase(ctx context.Context, req CreateWorkspaceBaseEnvironmentRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := createWorkspaceBaseEnvironmentRequestToWire(&req) if err != nil { return nil, err } @@ -158,7 +158,7 @@ func (c *internalClient) createWorkspaceBaseEnvironmentBase(ctx context.Context, // operation will asynchronously generate a materialized environment to optimize // dependency resolution and is only marked as done when the materialized // environment has been successfully generated or has failed. -func (c *internalClient) CreateWorkspaceBaseEnvironment(ctx context.Context, req *CreateWorkspaceBaseEnvironmentRequest, opts ...call.Option) (*CreateWorkspaceBaseEnvironmentOperation, error) { +func (c *internalClient) CreateWorkspaceBaseEnvironment(ctx context.Context, req CreateWorkspaceBaseEnvironmentRequest, opts ...call.Option) (*CreateWorkspaceBaseEnvironmentOperation, error) { operation, err := c.createWorkspaceBaseEnvironmentBase(ctx, req, opts...) if err != nil { return nil, err @@ -175,7 +175,7 @@ func (c *internalClient) CreateWorkspaceBaseEnvironment(ctx context.Context, req // CreateWorkspaceBaseEnvironmentOperation tracks the state of the long-running operation started by CreateWorkspaceBaseEnvironment. type CreateWorkspaceBaseEnvironmentOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -201,7 +201,7 @@ func (o *CreateWorkspaceBaseEnvironmentOperation) Metadata() (*WorkspaceBaseEnvi // Done refreshes the operation and reports whether it has completed. func (o *CreateWorkspaceBaseEnvironmentOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -219,7 +219,7 @@ func (o *CreateWorkspaceBaseEnvironmentOperation) Done(ctx context.Context, opts func (o *CreateWorkspaceBaseEnvironmentOperation) Wait(ctx context.Context, opts ...lro.Option) (*WorkspaceBaseEnvironment, error) { var result *WorkspaceBaseEnvironment poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -259,7 +259,7 @@ func (o *CreateWorkspaceBaseEnvironmentOperation) Wait(ctx context.Context, opts // Deletes a WorkspaceBaseEnvironment. Deleting a base environment may impact // linked notebooks and jobs. This operation is irreversible and should be // performed only when you are certain the environment is no longer needed. -func (c *internalClient) DeleteWorkspaceBaseEnvironment(ctx context.Context, req *DeleteWorkspaceBaseEnvironmentRequest, opts ...call.Option) error { +func (c *internalClient) DeleteWorkspaceBaseEnvironment(ctx context.Context, req DeleteWorkspaceBaseEnvironmentRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -273,7 +273,11 @@ func (c *internalClient) DeleteWorkspaceBaseEnvironment(ctx context.Context, req } pb := pathBuilder{} pb.literal("/api/environments/v1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -312,7 +316,7 @@ func (c *internalClient) DeleteWorkspaceBaseEnvironment(ctx context.Context, req // Gets the default WorkspaceBaseEnvironment configuration for the workspace. // Returns the current default base environment settings for both CPU and GPU // compute. -func (c *internalClient) GetDefaultWorkspaceBaseEnvironment(ctx context.Context, req *GetDefaultWorkspaceBaseEnvironmentRequest, opts ...call.Option) (*DefaultWorkspaceBaseEnvironment, error) { +func (c *internalClient) GetDefaultWorkspaceBaseEnvironment(ctx context.Context, req GetDefaultWorkspaceBaseEnvironmentRequest, opts ...call.Option) (*DefaultWorkspaceBaseEnvironment, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -326,7 +330,11 @@ func (c *internalClient) GetDefaultWorkspaceBaseEnvironment(ctx context.Context, } pb := pathBuilder{} pb.literal("/api/environments/v1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -373,7 +381,7 @@ func (c *internalClient) GetDefaultWorkspaceBaseEnvironment(ctx context.Context, // Gets the status of a long-running operation. Clients can use this method to // poll the operation result. -func (c *internalClient) getOperation(ctx context.Context, req *GetOperationRequest, opts ...call.Option) (*Operation, error) { +func (c *internalClient) getOperation(ctx context.Context, req GetOperationRequest, opts ...call.Option) (*Operation, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -387,7 +395,11 @@ func (c *internalClient) getOperation(ctx context.Context, req *GetOperationRequ } pb := pathBuilder{} pb.literal("/api/environments/v1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -433,7 +445,7 @@ func (c *internalClient) getOperation(ctx context.Context, req *GetOperationRequ } // Retrieves a WorkspaceBaseEnvironment by its name. -func (c *internalClient) GetWorkspaceBaseEnvironment(ctx context.Context, req *GetWorkspaceBaseEnvironmentRequest, opts ...call.Option) (*WorkspaceBaseEnvironment, error) { +func (c *internalClient) GetWorkspaceBaseEnvironment(ctx context.Context, req GetWorkspaceBaseEnvironmentRequest, opts ...call.Option) (*WorkspaceBaseEnvironment, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -447,7 +459,11 @@ func (c *internalClient) GetWorkspaceBaseEnvironment(ctx context.Context, req *G } pb := pathBuilder{} pb.literal("/api/environments/v1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -504,8 +520,8 @@ func (c *internalClient) GetWorkspaceBaseEnvironment(ctx context.Context, req *G // Databricks-provided base environments are versioned. For example, // `workspace-base-environments/databricks_ml_v5` corresponds to the ML // environment built on environment version 5. -func (c *internalClient) ListWorkspaceBaseEnvironments(ctx context.Context, req *ListWorkspaceBaseEnvironmentsRequest, opts ...call.Option) (*ListWorkspaceBaseEnvironmentsResponse, error) { - wireReq, err := listWorkspaceBaseEnvironmentsRequestToWire(req) +func (c *internalClient) ListWorkspaceBaseEnvironments(ctx context.Context, req ListWorkspaceBaseEnvironmentsRequest, opts ...call.Option) (*ListWorkspaceBaseEnvironmentsResponse, error) { + wireReq, err := listWorkspaceBaseEnvironmentsRequestToWire(&req) if err != nil { return nil, err } @@ -575,7 +591,7 @@ func (c *internalClient) ListWorkspaceBaseEnvironments(ctx context.Context, req // // For example: // -// for item, err := range c.ListWorkspaceBaseEnvironmentsIter(ctx, &ListWorkspaceBaseEnvironmentsRequest{}) { +// for item, err := range c.ListWorkspaceBaseEnvironmentsIter(ctx, ListWorkspaceBaseEnvironmentsRequest{}) { // if err != nil { // return err // } @@ -587,16 +603,13 @@ func (c *internalClient) ListWorkspaceBaseEnvironments(ctx context.Context, req // // Callers who need custom pagination logic should use // ListWorkspaceBaseEnvironments directly. -func (c *internalClient) ListWorkspaceBaseEnvironmentsIter(ctx context.Context, req *ListWorkspaceBaseEnvironmentsRequest, opts ...call.Option) iter.Seq2[*WorkspaceBaseEnvironment, error] { +func (c *internalClient) ListWorkspaceBaseEnvironmentsIter(ctx context.Context, req ListWorkspaceBaseEnvironmentsRequest, opts ...call.Option) iter.Seq2[*WorkspaceBaseEnvironment, error] { return func(yield func(*WorkspaceBaseEnvironment, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListWorkspaceBaseEnvironmentsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListWorkspaceBaseEnvironments(ctx, &pageReq, opts...) + resp, err := c.ListWorkspaceBaseEnvironments(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -619,8 +632,8 @@ func (c *internalClient) ListWorkspaceBaseEnvironmentsIter(ctx context.Context, // materialized environment and is only marked as done when the materialized // environment has been successfully generated or has failed. The existing // materialized environment remains available until it expires. -func (c *internalClient) refreshWorkspaceBaseEnvironmentBase(ctx context.Context, req *RefreshWorkspaceBaseEnvironmentRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := refreshWorkspaceBaseEnvironmentRequestToWire(req) +func (c *internalClient) refreshWorkspaceBaseEnvironmentBase(ctx context.Context, req RefreshWorkspaceBaseEnvironmentRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := refreshWorkspaceBaseEnvironmentRequestToWire(&req) if err != nil { return nil, err } @@ -641,7 +654,11 @@ func (c *internalClient) refreshWorkspaceBaseEnvironmentBase(ctx context.Context } pb := pathBuilder{} pb.literal("/api/environments/v1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/refresh") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -693,7 +710,7 @@ func (c *internalClient) refreshWorkspaceBaseEnvironmentBase(ctx context.Context // materialized environment and is only marked as done when the materialized // environment has been successfully generated or has failed. The existing // materialized environment remains available until it expires. -func (c *internalClient) RefreshWorkspaceBaseEnvironment(ctx context.Context, req *RefreshWorkspaceBaseEnvironmentRequest, opts ...call.Option) (*RefreshWorkspaceBaseEnvironmentOperation, error) { +func (c *internalClient) RefreshWorkspaceBaseEnvironment(ctx context.Context, req RefreshWorkspaceBaseEnvironmentRequest, opts ...call.Option) (*RefreshWorkspaceBaseEnvironmentOperation, error) { operation, err := c.refreshWorkspaceBaseEnvironmentBase(ctx, req, opts...) if err != nil { return nil, err @@ -710,7 +727,7 @@ func (c *internalClient) RefreshWorkspaceBaseEnvironment(ctx context.Context, re // RefreshWorkspaceBaseEnvironmentOperation tracks the state of the long-running operation started by RefreshWorkspaceBaseEnvironment. type RefreshWorkspaceBaseEnvironmentOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -736,7 +753,7 @@ func (o *RefreshWorkspaceBaseEnvironmentOperation) Metadata() (*WorkspaceBaseEnv // Done refreshes the operation and reports whether it has completed. func (o *RefreshWorkspaceBaseEnvironmentOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -754,7 +771,7 @@ func (o *RefreshWorkspaceBaseEnvironmentOperation) Done(ctx context.Context, opt func (o *RefreshWorkspaceBaseEnvironmentOperation) Wait(ctx context.Context, opts ...lro.Option) (*WorkspaceBaseEnvironment, error) { var result *WorkspaceBaseEnvironment poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -794,8 +811,8 @@ func (o *RefreshWorkspaceBaseEnvironmentOperation) Wait(ctx context.Context, opt // Updates the default WorkspaceBaseEnvironment configuration for the workspace. // Sets the specified base environments as the workspace defaults for CPU and/or // GPU compute. -func (c *internalClient) UpdateDefaultWorkspaceBaseEnvironment(ctx context.Context, req *UpdateDefaultWorkspaceBaseEnvironmentRequest, opts ...call.Option) (*DefaultWorkspaceBaseEnvironment, error) { - wireReq, err := updateDefaultWorkspaceBaseEnvironmentRequestToWire(req) +func (c *internalClient) UpdateDefaultWorkspaceBaseEnvironment(ctx context.Context, req UpdateDefaultWorkspaceBaseEnvironmentRequest, opts ...call.Option) (*DefaultWorkspaceBaseEnvironment, error) { + wireReq, err := updateDefaultWorkspaceBaseEnvironmentRequestToWire(&req) if err != nil { return nil, err } @@ -816,7 +833,11 @@ func (c *internalClient) UpdateDefaultWorkspaceBaseEnvironment(ctx context.Conte } pb := pathBuilder{} pb.literal("/api/environments/v1/") - pb.singleSegment(*req.DefaultWorkspaceBaseEnvironment.Name) + if req.DefaultWorkspaceBaseEnvironment == nil || req.DefaultWorkspaceBaseEnvironment.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DefaultWorkspaceBaseEnvironment.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -870,8 +891,8 @@ func (c *internalClient) UpdateDefaultWorkspaceBaseEnvironment(ctx context.Conte // environment and is only marked as done when the materialized environment has // been successfully generated or has failed. The existing materialized // environment remains available until it expires. -func (c *internalClient) updateWorkspaceBaseEnvironmentBase(ctx context.Context, req *UpdateWorkspaceBaseEnvironmentRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := updateWorkspaceBaseEnvironmentRequestToWire(req) +func (c *internalClient) updateWorkspaceBaseEnvironmentBase(ctx context.Context, req UpdateWorkspaceBaseEnvironmentRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := updateWorkspaceBaseEnvironmentRequestToWire(&req) if err != nil { return nil, err } @@ -892,7 +913,11 @@ func (c *internalClient) updateWorkspaceBaseEnvironmentBase(ctx context.Context, } pb := pathBuilder{} pb.literal("/api/environments/v1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -943,7 +968,7 @@ func (c *internalClient) updateWorkspaceBaseEnvironmentBase(ctx context.Context, // environment and is only marked as done when the materialized environment has // been successfully generated or has failed. The existing materialized // environment remains available until it expires. -func (c *internalClient) UpdateWorkspaceBaseEnvironment(ctx context.Context, req *UpdateWorkspaceBaseEnvironmentRequest, opts ...call.Option) (*UpdateWorkspaceBaseEnvironmentOperation, error) { +func (c *internalClient) UpdateWorkspaceBaseEnvironment(ctx context.Context, req UpdateWorkspaceBaseEnvironmentRequest, opts ...call.Option) (*UpdateWorkspaceBaseEnvironmentOperation, error) { operation, err := c.updateWorkspaceBaseEnvironmentBase(ctx, req, opts...) if err != nil { return nil, err @@ -960,7 +985,7 @@ func (c *internalClient) UpdateWorkspaceBaseEnvironment(ctx context.Context, req // UpdateWorkspaceBaseEnvironmentOperation tracks the state of the long-running operation started by UpdateWorkspaceBaseEnvironment. type UpdateWorkspaceBaseEnvironmentOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -986,7 +1011,7 @@ func (o *UpdateWorkspaceBaseEnvironmentOperation) Metadata() (*WorkspaceBaseEnvi // Done refreshes the operation and reports whether it has completed. func (o *UpdateWorkspaceBaseEnvironmentOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -1004,7 +1029,7 @@ func (o *UpdateWorkspaceBaseEnvironmentOperation) Done(ctx context.Context, opts func (o *UpdateWorkspaceBaseEnvironmentOperation) Wait(ctx context.Context, opts ...lro.Option) (*WorkspaceBaseEnvironment, error) { var result *WorkspaceBaseEnvironment poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } diff --git a/environments/v1/genhelper.go b/environments/v1/genhelper.go old mode 100755 new mode 100644 index da76122..00a2d33 --- a/environments/v1/genhelper.go +++ b/environments/v1/genhelper.go @@ -220,11 +220,12 @@ func generateRequestID() string { return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:16]) } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -237,13 +238,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..79fdff6 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,51 @@ +# Examples + +Each subdirectory contains a complete program for one Databricks Go SDK task. +Choose the example closest to what you want to build, then copy it or run it +from this directory. + +All programs use the `examples` build tag. Include it when running one: + +```sh +go run -tags=examples ./time_types +``` + +## Choose an example + +| Program | What it demonstrates | Required setup | +| --- | --- | --- | +| `authentication/resolution` | Create a client with automatic credential resolution | A profile or authentication environment variables (see below) | +| `authentication/m2m` | Construct and pass OAuth M2M credentials explicitly | `DATABRICKS_HOST`, `DATABRICKS_CLIENT_ID`, and `DATABRICKS_CLIENT_SECRET` | +| `authentication/custom` | Implement `auth.Credentials` for an external token provider | Set `workspaceHost` in the program and provide `EXTERNAL_ACCESS_TOKEN` | +| `client_options` | Set a profile, logger, and request timeout | A Databricks profile | +| `pagination` | Iterate across pages and stop after enough results | A profile or authentication environment variables | +| `error_handling` | Inspect the code, HTTP status, and message of an API error | A profile or authentication environment variables | +| `field_masks` | Build an update with a typed field mask, including a oneof path and a field to clear | None | +| `oneofs` | Construct and inspect mutually exclusive oneof variants | None | +| `time_types` | Convert SDK timestamp and duration values | None | + +## Authenticate to a workspace + +For examples that use a workspace, install the +[Databricks CLI](https://docs.databricks.com/aws/en/dev-tools/cli/install), then +log in and select the profile explicitly: + +```sh +databricks auth login --host https:// --profile SDK_EXAMPLES +DATABRICKS_CONFIG_PROFILE=SDK_EXAMPLES go run -tags=examples ./pagination +``` + +Alternatively, provide credentials through environment variables: + +```sh +DATABRICKS_HOST=https:// \ +DATABRICKS_CLIENT_ID= \ +DATABRICKS_CLIENT_SECRET= \ + go run -tags=examples ./pagination +``` + +The `client_options` example passes the profile directly as a client option: + +```sh +go run -tags=examples ./client_options -profile SDK_EXAMPLES +``` diff --git a/examples/authentication/custom/main.go b/examples/authentication/custom/main.go new file mode 100644 index 0000000..0bf008d --- /dev/null +++ b/examples/authentication/custom/main.go @@ -0,0 +1,58 @@ +//go:build examples + +package main + +import ( + "context" + "fmt" + "log" + "os" + + "github.com/databricks/sdk-go/auth" + "github.com/databricks/sdk-go/jobs/v2" + "github.com/databricks/sdk-go/options/client" +) + +type externalCredentials struct { + token func(context.Context) (string, error) +} + +const workspaceHost = "https://" + +func (externalCredentials) Name() string { + // Name gives SDK logs and telemetry a stable label for this auth type. + return "external" +} + +func (c externalCredentials) AuthHeaders(ctx context.Context) ([]auth.Header, error) { + // The SDK calls AuthHeaders when signing a request, so an implementation can + // retrieve or refresh tokens from an external provider here. + token, err := c.token(ctx) + if err != nil { + return nil, fmt.Errorf("getting external token: %w", err) + } + return []auth.Header{{Key: "Authorization", Value: "Bearer " + token}}, nil +} + +func main() { + creds := externalCredentials{token: func(context.Context) (string, error) { + // Replace this environment lookup with a call to your external token provider. + token := os.Getenv("EXTERNAL_ACCESS_TOKEN") + if token == "" { + return "", fmt.Errorf("EXTERNAL_ACCESS_TOKEN must be set") + } + return token, nil + }} + + ctx := context.Background() + c, err := jobs.NewClient(ctx, client.WithHost(workspaceHost), client.WithCredentials(creds)) + if err != nil { + log.Fatalf("creating Jobs client: %v", err) + } + // Use a small read request to confirm that the supplied credentials work. + if _, err := c.ListJobs(ctx, jobs.ListJobsRequest{Limit: new(1)}); err != nil { + log.Fatalf("listing jobs: %v", err) + } + + fmt.Printf("Authenticated successfully with %s credentials\n", creds.Name()) +} diff --git a/examples/authentication/m2m/main.go b/examples/authentication/m2m/main.go new file mode 100644 index 0000000..e97a18d --- /dev/null +++ b/examples/authentication/m2m/main.go @@ -0,0 +1,48 @@ +//go:build examples + +package main + +import ( + "context" + "fmt" + "log" + "os" + + "github.com/databricks/sdk-go/auth" + "github.com/databricks/sdk-go/auth/credentials" + "github.com/databricks/sdk-go/jobs/v2" + "github.com/databricks/sdk-go/options/client" +) + +func main() { + host := os.Getenv("DATABRICKS_HOST") + clientID := os.Getenv("DATABRICKS_CLIENT_ID") + clientSecret := os.Getenv("DATABRICKS_CLIENT_SECRET") + if host == "" || clientID == "" || clientSecret == "" { + log.Fatal("DATABRICKS_HOST, DATABRICKS_CLIENT_ID, and DATABRICKS_CLIENT_SECRET must be set") + } + + // Passing these credentials to the client below ensures it uses M2M, even + // if other authentication settings are available. + tokenProvider, err := credentials.NewM2MCredentials(credentials.M2MOptions{ + Host: host, + ClientID: clientID, + ClientSecret: clientSecret, + }) + if err != nil { + log.Fatalf("creating M2M credentials: %v", err) + } + // Cache the provider so access tokens are reused until they near expiry. + creds := auth.NewTokenCredentials("oauth-m2m", auth.NewCachedTokenProvider(tokenProvider)) + + ctx := context.Background() + c, err := jobs.NewClient(ctx, client.WithHost(host), client.WithCredentials(creds)) + if err != nil { + log.Fatalf("creating Jobs client: %v", err) + } + if _, err := c.ListJobs(ctx, jobs.ListJobsRequest{Limit: new(1)}); err != nil { + log.Fatalf("listing jobs: %v", err) + } + + fmt.Println("Authenticated successfully with explicit M2M credentials") +} diff --git a/examples/authentication/resolution/main.go b/examples/authentication/resolution/main.go new file mode 100644 index 0000000..b62a8f7 --- /dev/null +++ b/examples/authentication/resolution/main.go @@ -0,0 +1,34 @@ +//go:build examples + +package main + +import ( + "context" + "fmt" + "log" + + "github.com/databricks/sdk-go/jobs/v2" +) + +func main() { + if err := run(context.Background()); err != nil { + log.Fatal(err) + } +} + +func run(ctx context.Context) error { + // DATABRICKS_CONFIG_PROFILE selects a profile from ~/.databrickscfg. If it + // is unset, the SDK uses default_profile from [__settings__], then falls + // back to [DEFAULT]. DATABRICKS_* values override values from the profile. + c, err := jobs.NewClient(ctx) + if err != nil { + return fmt.Errorf("creating Jobs client: %w", err) + } + // Use a small read request to confirm that the resolved credentials work. + if _, err := c.ListJobs(ctx, jobs.ListJobsRequest{Limit: new(1)}); err != nil { + return fmt.Errorf("listing jobs: %w", err) + } + + fmt.Println("Authenticated successfully") + return nil +} diff --git a/examples/client_options/main.go b/examples/client_options/main.go new file mode 100644 index 0000000..6063244 --- /dev/null +++ b/examples/client_options/main.go @@ -0,0 +1,49 @@ +//go:build examples + +package main + +import ( + "context" + "flag" + "fmt" + "log" + "log/slog" + "os" + "time" + + "github.com/databricks/sdk-go/jobs/v2" + "github.com/databricks/sdk-go/options/client" +) + +func main() { + profile := flag.String("profile", "", "Databricks configuration profile") + flag.Parse() + if *profile == "" { + log.Fatal("-profile must be set") + } + + if err := run(context.Background(), *profile); err != nil { + log.Fatal(err) + } +} + +func run(ctx context.Context, profile string) error { + logger := slog.New(slog.NewTextHandler(os.Stderr, nil)) + // WithProfile selects a profile in code instead of through + // DATABRICKS_CONFIG_PROFILE. WithLogger enables SDK logs, and WithTimeout + // sets the default timeout for API calls made by this client. + c, err := jobs.NewClient(ctx, + client.WithProfile(profile), + client.WithLogger(logger), + client.WithTimeout(30*time.Second), + ) + if err != nil { + return fmt.Errorf("creating Jobs client: %w", err) + } + if _, err := c.ListJobs(ctx, jobs.ListJobsRequest{Limit: new(1)}); err != nil { + return fmt.Errorf("listing jobs: %w", err) + } + + fmt.Printf("Configured client with profile %q\n", profile) + return nil +} diff --git a/examples/error_handling/main.go b/examples/error_handling/main.go new file mode 100644 index 0000000..82e9eb3 --- /dev/null +++ b/examples/error_handling/main.go @@ -0,0 +1,43 @@ +//go:build examples + +package main + +import ( + "context" + "errors" + "fmt" + "log" + + "github.com/databricks/sdk-go/core/apierr" + "github.com/databricks/sdk-go/jobs/v2" +) + +func main() { + if err := run(context.Background()); err != nil { + log.Fatal(err) + } +} + +func run(ctx context.Context) error { + c, err := jobs.NewClient(ctx) + if err != nil { + return fmt.Errorf("creating Jobs client: %w", err) + } + + // Job IDs are positive, so this request deterministically returns an API error. + _, err = c.GetJob(ctx, jobs.GetJobRequest{JobId: new(int64(-1))}) + if err == nil { + return errors.New("expected the invalid job lookup to fail") + } + + // APIError preserves the structured Databricks error response, and + // errors.As also finds it through wrapped errors. + var apiError *apierr.APIError + if !errors.As(err, &apiError) { + return fmt.Errorf("getting invalid job returned an unexpected error type: %w", err) + } + fmt.Printf("Code: %s\n", apiError.Code()) + fmt.Printf("HTTP status: %d\n", apiError.HTTPStatusCode()) + fmt.Printf("Message: %s\n", apiError.Message()) + return nil +} diff --git a/examples/field_masks/main.go b/examples/field_masks/main.go new file mode 100644 index 0000000..b7cb529 --- /dev/null +++ b/examples/field_masks/main.go @@ -0,0 +1,50 @@ +//go:build examples + +package main + +import ( + "fmt" + "log" + + "github.com/databricks/sdk-go/core/types" + "github.com/databricks/sdk-go/dataquality/v1" +) + +func main() { + // NewFieldMask validates these API field paths against Monitor and its nested + // generated types. Only fields in the mask are updated. + updateMask, err := types.NewFieldMask[dataquality.Monitor]( + "data_profiling_config.output_schema_id", + // Oneof variants use their API field name directly in the mask. + "data_profiling_config.time_series", + "data_profiling_config.schedule", + ) + if err != nil { + log.Fatal(err) + } + + // Schedule is intentionally unset. Because its path is present in the mask, + // this request clears the current schedule while updating the other fields. + request := &dataquality.UpdateMonitorRequest{ + // These fields identify the monitor. UpdateMask applies to the Monitor + // resource below, not to these request fields. + ObjectType: new("table"), + ObjectId: new("00000000-0000-0000-0000-000000000000"), + Monitor: &dataquality.Monitor{ + DataProfilingConfig: &dataquality.DataProfilingConfig{ + OutputSchemaId: new("main.monitoring"), + AnalysisConfig: &dataquality.DataProfilingConfig_AnalysisConfig_TimeSeries{ + TimeSeries: dataquality.TimeSeriesConfig{ + TimestampColumn: new("event_time"), + }, + }, + }, + }, + UpdateMask: updateMask, + } + + config := request.Monitor.DataProfilingConfig + fmt.Printf("Update %s %s with mask %s\n", *request.ObjectType, *request.ObjectId, request.UpdateMask) + fmt.Printf("Output schema: %s\n", *config.OutputSchemaId) + fmt.Printf("Clear schedule: %t\n", config.Schedule == nil) +} diff --git a/examples/go.mod b/examples/go.mod new file mode 100644 index 0000000..ca2d57a --- /dev/null +++ b/examples/go.mod @@ -0,0 +1,34 @@ +module github.com/databricks/sdk-go/examples + +go 1.26.0 + +replace github.com/databricks/sdk-go/auth => ../auth + +replace github.com/databricks/sdk-go/core => ../core + +replace github.com/databricks/sdk-go/dataquality => ../dataquality + +replace github.com/databricks/sdk-go/jobs => ../jobs + +replace github.com/databricks/sdk-go/options => ../options + +require ( + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/dataquality v0.0.0-00010101000000-000000000000 + github.com/databricks/sdk-go/jobs v0.0.0-00010101000000-000000000000 + github.com/databricks/sdk-go/options v0.0.1-dev.2 +) + +require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect +) diff --git a/examples/go.sum b/examples/go.sum new file mode 100644 index 0000000..d7c0349 --- /dev/null +++ b/examples/go.sum @@ -0,0 +1,22 @@ +github.com/databricks/databricks-sdk-go v0.92.0 h1:Pvm/LvEXetOYJPgQFeewhmtkKC4z79AK3PHC5tlC+VQ= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= +golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/examples/oneofs/main.go b/examples/oneofs/main.go new file mode 100644 index 0000000..de3ebe6 --- /dev/null +++ b/examples/oneofs/main.go @@ -0,0 +1,45 @@ +//go:build examples + +package main + +import ( + "errors" + "fmt" + "log" + + "github.com/databricks/sdk-go/jobs/v2" +) + +func main() { + // Oneof fields use a wrapper for each variant. Choose a variant by assigning + // its wrapper to the interface field. + task := jobs.TaskSettings{ + TaskKey: new("hello_world"), + Task: &jobs.TaskSettings_Task_SparkPythonTask{ + SparkPythonTask: jobs.SparkPythonTask{ + PythonFile: new("/Workspace/Users/user@example.com/hello.py"), + Source: jobs.Source_Workspace, + }, + }, + } + + if err := describeTask(task); err != nil { + log.Fatal(err) + } +} + +func describeTask(task jobs.TaskSettings) error { + // A type switch identifies the configured variant and provides typed access + // to its fields. + switch configuredTask := task.Task.(type) { + case *jobs.TaskSettings_Task_NotebookTask: + fmt.Printf("Notebook: %s\n", *configuredTask.NotebookTask.NotebookPath) + case *jobs.TaskSettings_Task_SparkPythonTask: + fmt.Printf("Python file: %s\n", *configuredTask.SparkPythonTask.PythonFile) + case nil: + return errors.New("task is missing its configuration") + default: + return fmt.Errorf("unsupported task configuration %T", configuredTask) + } + return nil +} diff --git a/examples/pagination/main.go b/examples/pagination/main.go new file mode 100644 index 0000000..c8cf7d1 --- /dev/null +++ b/examples/pagination/main.go @@ -0,0 +1,52 @@ +//go:build examples + +package main + +import ( + "context" + "fmt" + "log" + + "github.com/databricks/sdk-go/jobs/v2" +) + +const ( + pageSize = 5 + jobsToList = 12 +) + +func main() { + if err := run(context.Background()); err != nil { + log.Fatal(err) + } +} + +func run(ctx context.Context) error { + c, err := jobs.NewClient(ctx) + if err != nil { + return fmt.Errorf("creating Jobs client: %w", err) + } + + count := 0 + // Limit controls the page size. The iterator fetches more results as needed. + for job, err := range c.ListJobsIter(ctx, jobs.ListJobsRequest{Limit: new(pageSize)}) { + if err != nil { + return fmt.Errorf("listing jobs: %w", err) + } + count++ + if job.JobId == nil { + return fmt.Errorf("job %d omitted its ID", count) + } + if job.Settings != nil && job.Settings.Name != nil { + fmt.Printf("%d: %s\n", *job.JobId, *job.Settings.Name) + } else { + fmt.Println(*job.JobId) + } + if count == jobsToList { + break + } + } + + fmt.Printf("Listed %d jobs with a page size of %d.\n", count, pageSize) + return nil +} diff --git a/examples/time_types/main.go b/examples/time_types/main.go new file mode 100644 index 0000000..d7dfa5c --- /dev/null +++ b/examples/time_types/main.go @@ -0,0 +1,29 @@ +//go:build examples + +package main + +import ( + "fmt" + "log" + "time" + + "github.com/databricks/sdk-go/core/types" +) + +func main() { + // Use these constructors when assigning time values to SDK request fields; + // use AsTime and AsDuration when consuming values from SDK responses. + startedAt := types.NewFromTime(time.Date(2026, time.January, 15, 10, 30, 0, 0, time.UTC)) + timeout := types.NewFromDuration(15 * time.Minute) + finishedAt := startedAt.Add(timeout) + + // Arithmetic does not validate the result; check it before sending it to an API. + if err := finishedAt.CheckValid(); err != nil { + log.Fatal(err) + } + + fmt.Printf("Started: %s\n", startedAt) + fmt.Printf("Finished: %s\n", finishedAt) + fmt.Printf("Elapsed: %s\n", finishedAt.AsTime().Sub(startedAt.AsTime())) + fmt.Printf("Timeout as time.Duration: %s\n", timeout.AsDuration()) +} diff --git a/experiments/CHANGELOG.md b/experiments/CHANGELOG.md index 6224c04..19f237c 100644 --- a/experiments/CHANGELOG.md +++ b/experiments/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/experiments/go.mod b/experiments/go.mod index ee27878..75241df 100644 --- a/experiments/go.mod +++ b/experiments/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/experiments/internal/version.go b/experiments/internal/version.go index 8c126ea..79237ad 100644 --- a/experiments/internal/version.go +++ b/experiments/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-experiments" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/experiments/v1/client.go b/experiments/v1/client.go old mode 100755 new mode 100644 index 05cadf9..dfeed2a --- a/experiments/v1/client.go +++ b/experiments/v1/client.go @@ -82,8 +82,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Throws `RESOURCE_ALREADY_EXISTS` if an experiment with the given name exists. // Note: In some contexts, this error may be remapped to `ALREADY_EXISTS`. To be // safe, clients should check for both error codes. -func (c *internalClient) CreateExperiment(ctx context.Context, req *CreateExperimentRequest, opts ...call.Option) (*CreateExperimentResponse, error) { - wireReq, err := createExperimentRequestToWire(req) +func (c *internalClient) CreateExperiment(ctx context.Context, req CreateExperimentRequest, opts ...call.Option) (*CreateExperimentResponse, error) { + wireReq, err := createExperimentRequestToWire(&req) if err != nil { return nil, err } @@ -148,8 +148,8 @@ func (c *internalClient) CreateExperiment(ctx context.Context, req *CreateExperi } // Create a logged model. -func (c *internalClient) CreateLoggedModel(ctx context.Context, req *CreateLoggedModelRequest, opts ...call.Option) (*CreateLoggedModelResponse, error) { - wireReq, err := createLoggedModelRequestToWire(req) +func (c *internalClient) CreateLoggedModel(ctx context.Context, req CreateLoggedModelRequest, opts ...call.Option) (*CreateLoggedModelResponse, error) { + wireReq, err := createLoggedModelRequestToWire(&req) if err != nil { return nil, err } @@ -217,8 +217,8 @@ func (c *internalClient) CreateLoggedModel(ctx context.Context, req *CreateLogge // of a machine learning or data ETL pipeline. MLflow uses runs to track the // `mlflowParam`, `mlflowMetric`, and `mlflowRunTag` associated with a single // execution. -func (c *internalClient) CreateRun(ctx context.Context, req *CreateRunRequest, opts ...call.Option) (*CreateRunResponse, error) { - wireReq, err := createRunRequestToWire(req) +func (c *internalClient) CreateRun(ctx context.Context, req CreateRunRequest, opts ...call.Option) (*CreateRunResponse, error) { + wireReq, err := createRunRequestToWire(&req) if err != nil { return nil, err } @@ -285,8 +285,8 @@ func (c *internalClient) CreateRun(ctx context.Context, req *CreateRunRequest, o // Marks an experiment and associated metadata, runs, metrics, params, and tags // for deletion. If the experiment uses FileStore, artifacts associated with the // experiment are also deleted. -func (c *internalClient) DeleteExperiment(ctx context.Context, req *DeleteExperimentRequest, opts ...call.Option) (*DeleteExperimentResponse, error) { - wireReq, err := deleteExperimentRequestToWire(req) +func (c *internalClient) DeleteExperiment(ctx context.Context, req DeleteExperimentRequest, opts ...call.Option) (*DeleteExperimentResponse, error) { + wireReq, err := deleteExperimentRequestToWire(&req) if err != nil { return nil, err } @@ -345,7 +345,7 @@ func (c *internalClient) DeleteExperiment(ctx context.Context, req *DeleteExperi } // Delete a logged model. -func (c *internalClient) DeleteLoggedModel(ctx context.Context, req *DeleteLoggedModelRequest, opts ...call.Option) (*DeleteLoggedModelResponse, error) { +func (c *internalClient) DeleteLoggedModel(ctx context.Context, req DeleteLoggedModelRequest, opts ...call.Option) (*DeleteLoggedModelResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -359,7 +359,11 @@ func (c *internalClient) DeleteLoggedModel(ctx context.Context, req *DeleteLogge } pb := pathBuilder{} pb.literal("/api/2.0/mlflow/logged-models/") - pb.singleSegment(*req.ModelId) + if req.ModelId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ModelId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -399,7 +403,7 @@ func (c *internalClient) DeleteLoggedModel(ctx context.Context, req *DeleteLogge } // Delete a tag on a logged model. -func (c *internalClient) DeleteLoggedModelTag(ctx context.Context, req *DeleteLoggedModelTagRequest, opts ...call.Option) (*DeleteLoggedModelTagResponse, error) { +func (c *internalClient) DeleteLoggedModelTag(ctx context.Context, req DeleteLoggedModelTagRequest, opts ...call.Option) (*DeleteLoggedModelTagResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -413,9 +417,17 @@ func (c *internalClient) DeleteLoggedModelTag(ctx context.Context, req *DeleteLo } pb := pathBuilder{} pb.literal("/api/2.0/mlflow/logged-models/") - pb.singleSegment(*req.ModelId) + if req.ModelId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ModelId) + } pb.literal("/tags/") - pb.singleSegment(*req.TagKey) + if req.TagKey == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.TagKey) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -455,8 +467,8 @@ func (c *internalClient) DeleteLoggedModelTag(ctx context.Context, req *DeleteLo } // Marks a run for deletion. -func (c *internalClient) DeleteRun(ctx context.Context, req *DeleteRunRequest, opts ...call.Option) (*DeleteRunResponse, error) { - wireReq, err := deleteRunRequestToWire(req) +func (c *internalClient) DeleteRun(ctx context.Context, req DeleteRunRequest, opts ...call.Option) (*DeleteRunResponse, error) { + wireReq, err := deleteRunRequestToWire(&req) if err != nil { return nil, err } @@ -517,8 +529,8 @@ func (c *internalClient) DeleteRun(ctx context.Context, req *DeleteRunRequest, o // Bulk delete runs in an experiment that were created prior to or at the // specified timestamp. Deletes at most max_runs per request. To call this API // from a Databricks Notebook in Python, you can use the client code snippet on -func (c *internalClient) DeleteRuns(ctx context.Context, req *DeleteRunsRequest, opts ...call.Option) (*DeleteRunsResponse, error) { - wireReq, err := deleteRunsRequestToWire(req) +func (c *internalClient) DeleteRuns(ctx context.Context, req DeleteRunsRequest, opts ...call.Option) (*DeleteRunsResponse, error) { + wireReq, err := deleteRunsRequestToWire(&req) if err != nil { return nil, err } @@ -584,8 +596,8 @@ func (c *internalClient) DeleteRuns(ctx context.Context, req *DeleteRunsRequest, // Deletes a tag on a run. Tags are run metadata that can be updated during a // run and after a run completes. -func (c *internalClient) DeleteTag(ctx context.Context, req *DeleteTagRequest, opts ...call.Option) (*DeleteTagResponse, error) { - wireReq, err := deleteTagRequestToWire(req) +func (c *internalClient) DeleteTag(ctx context.Context, req DeleteTagRequest, opts ...call.Option) (*DeleteTagResponse, error) { + wireReq, err := deleteTagRequestToWire(&req) if err != nil { return nil, err } @@ -644,8 +656,8 @@ func (c *internalClient) DeleteTag(ctx context.Context, req *DeleteTagRequest, o } // Finalize a logged model. -func (c *internalClient) FinalizeLoggedModel(ctx context.Context, req *FinalizeLoggedModelRequest, opts ...call.Option) (*FinalizeLoggedModelResponse, error) { - wireReq, err := finalizeLoggedModelRequestToWire(req) +func (c *internalClient) FinalizeLoggedModel(ctx context.Context, req FinalizeLoggedModelRequest, opts ...call.Option) (*FinalizeLoggedModelResponse, error) { + wireReq, err := finalizeLoggedModelRequestToWire(&req) if err != nil { return nil, err } @@ -666,7 +678,11 @@ func (c *internalClient) FinalizeLoggedModel(ctx context.Context, req *FinalizeL } pb := pathBuilder{} pb.literal("/api/2.0/mlflow/logged-models/") - pb.singleSegment(*req.ModelId) + if req.ModelId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ModelId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -713,8 +729,8 @@ func (c *internalClient) FinalizeLoggedModel(ctx context.Context, req *FinalizeL } // Gets metadata for an experiment. This method works on deleted experiments. -func (c *internalClient) GetExperiment(ctx context.Context, req *GetExperimentRequest, opts ...call.Option) (*GetExperimentResponse, error) { - wireReq, err := getExperimentRequestToWire(req) +func (c *internalClient) GetExperiment(ctx context.Context, req GetExperimentRequest, opts ...call.Option) (*GetExperimentResponse, error) { + wireReq, err := getExperimentRequestToWire(&req) if err != nil { return nil, err } @@ -785,8 +801,8 @@ func (c *internalClient) GetExperiment(ctx context.Context, req *GetExperimentRe // // Throws `RESOURCE_DOES_NOT_EXIST` if no experiment with the specified name // exists. -func (c *internalClient) GetExperimentByName(ctx context.Context, req *GetExperimentByNameRequest, opts ...call.Option) (*GetExperimentByNameResponse, error) { - wireReq, err := getExperimentByNameRequestToWire(req) +func (c *internalClient) GetExperimentByName(ctx context.Context, req GetExperimentByNameRequest, opts ...call.Option) (*GetExperimentByNameResponse, error) { + wireReq, err := getExperimentByNameRequestToWire(&req) if err != nil { return nil, err } @@ -849,7 +865,7 @@ func (c *internalClient) GetExperimentByName(ctx context.Context, req *GetExperi } // Get a logged model. -func (c *internalClient) GetLoggedModel(ctx context.Context, req *GetLoggedModelRequest, opts ...call.Option) (*GetLoggedModelResponse, error) { +func (c *internalClient) GetLoggedModel(ctx context.Context, req GetLoggedModelRequest, opts ...call.Option) (*GetLoggedModelResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -863,7 +879,11 @@ func (c *internalClient) GetLoggedModel(ctx context.Context, req *GetLoggedModel } pb := pathBuilder{} pb.literal("/api/2.0/mlflow/logged-models/") - pb.singleSegment(*req.ModelId) + if req.ModelId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ModelId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -914,8 +934,8 @@ func (c *internalClient) GetLoggedModel(ctx context.Context, req *GetLoggedModel // // If there are multiple values with the latest timestamp, return the maximum of // these values. -func (c *internalClient) GetRun(ctx context.Context, req *GetRunRequest, opts ...call.Option) (*GetRunResponse, error) { - wireReq, err := getRunRequestToWire(req) +func (c *internalClient) GetRun(ctx context.Context, req GetRunRequest, opts ...call.Option) (*GetRunResponse, error) { + wireReq, err := getRunRequestToWire(&req) if err != nil { return nil, err } @@ -986,8 +1006,8 @@ func (c *internalClient) GetRun(ctx context.Context, req *GetRunRequest, opts .. // `/api/2.0/fs/directories{directory_path}` for listing artifacts in UC // Volumes, which supports pagination. See [List directory contents | Files // API](/api/workspace/files/listdirectorycontents). -func (c *internalClient) ListArtifacts(ctx context.Context, req *ListArtifactsRequest, opts ...call.Option) (*ListArtifactsResponse, error) { - wireReq, err := listArtifactsRequestToWire(req) +func (c *internalClient) ListArtifacts(ctx context.Context, req ListArtifactsRequest, opts ...call.Option) (*ListArtifactsResponse, error) { + wireReq, err := listArtifactsRequestToWire(&req) if err != nil { return nil, err } @@ -1063,7 +1083,7 @@ func (c *internalClient) ListArtifacts(ctx context.Context, req *ListArtifactsRe // // For example: // -// for item, err := range c.ListArtifactsIter(ctx, &ListArtifactsRequest{}) { +// for item, err := range c.ListArtifactsIter(ctx, ListArtifactsRequest{}) { // if err != nil { // return err // } @@ -1075,16 +1095,13 @@ func (c *internalClient) ListArtifacts(ctx context.Context, req *ListArtifactsRe // // Callers who need custom pagination logic should use // ListArtifacts directly. -func (c *internalClient) ListArtifactsIter(ctx context.Context, req *ListArtifactsRequest, opts ...call.Option) iter.Seq2[*FileInfo, error] { +func (c *internalClient) ListArtifactsIter(ctx context.Context, req ListArtifactsRequest, opts ...call.Option) iter.Seq2[*FileInfo, error] { return func(yield func(*FileInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListArtifactsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListArtifacts(ctx, &pageReq, opts...) + resp, err := c.ListArtifacts(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1103,8 +1120,8 @@ func (c *internalClient) ListArtifactsIter(ctx context.Context, req *ListArtifac } // Gets a list of all experiments. -func (c *internalClient) ListExperiments(ctx context.Context, req *ListExperimentsRequest, opts ...call.Option) (*ListExperimentsResponse, error) { - wireReq, err := listExperimentsRequestToWire(req) +func (c *internalClient) ListExperiments(ctx context.Context, req ListExperimentsRequest, opts ...call.Option) (*ListExperimentsResponse, error) { + wireReq, err := listExperimentsRequestToWire(&req) if err != nil { return nil, err } @@ -1179,7 +1196,7 @@ func (c *internalClient) ListExperiments(ctx context.Context, req *ListExperimen // // For example: // -// for item, err := range c.ListExperimentsIter(ctx, &ListExperimentsRequest{}) { +// for item, err := range c.ListExperimentsIter(ctx, ListExperimentsRequest{}) { // if err != nil { // return err // } @@ -1191,16 +1208,13 @@ func (c *internalClient) ListExperiments(ctx context.Context, req *ListExperimen // // Callers who need custom pagination logic should use // ListExperiments directly. -func (c *internalClient) ListExperimentsIter(ctx context.Context, req *ListExperimentsRequest, opts ...call.Option) iter.Seq2[*Experiment, error] { +func (c *internalClient) ListExperimentsIter(ctx context.Context, req ListExperimentsRequest, opts ...call.Option) iter.Seq2[*Experiment, error] { return func(yield func(*Experiment, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListExperimentsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListExperiments(ctx, &pageReq, opts...) + resp, err := c.ListExperiments(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1219,8 +1233,8 @@ func (c *internalClient) ListExperimentsIter(ctx context.Context, req *ListExper } // Gets a list of all values for the specified metric for a given run. -func (c *internalClient) ListMetricHistory(ctx context.Context, req *ListMetricHistoryRequest, opts ...call.Option) (*GetMetricHistoryResponse, error) { - wireReq, err := listMetricHistoryRequestToWire(req) +func (c *internalClient) ListMetricHistory(ctx context.Context, req ListMetricHistoryRequest, opts ...call.Option) (*GetMetricHistoryResponse, error) { + wireReq, err := listMetricHistoryRequestToWire(&req) if err != nil { return nil, err } @@ -1299,7 +1313,7 @@ func (c *internalClient) ListMetricHistory(ctx context.Context, req *ListMetricH // // For example: // -// for item, err := range c.ListMetricHistoryIter(ctx, &ListMetricHistoryRequest{}) { +// for item, err := range c.ListMetricHistoryIter(ctx, ListMetricHistoryRequest{}) { // if err != nil { // return err // } @@ -1311,16 +1325,13 @@ func (c *internalClient) ListMetricHistory(ctx context.Context, req *ListMetricH // // Callers who need custom pagination logic should use // ListMetricHistory directly. -func (c *internalClient) ListMetricHistoryIter(ctx context.Context, req *ListMetricHistoryRequest, opts ...call.Option) iter.Seq2[*Metric, error] { +func (c *internalClient) ListMetricHistoryIter(ctx context.Context, req ListMetricHistoryRequest, opts ...call.Option) iter.Seq2[*Metric, error] { return func(yield func(*Metric, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListMetricHistoryRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListMetricHistory(ctx, &pageReq, opts...) + resp, err := c.ListMetricHistory(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1381,8 +1392,8 @@ func (c *internalClient) ListMetricHistoryIter(ctx context.Context, req *ListMet // * Metric keys, param keys, and tag keys can be up to 250 characters in length // // * Parameter and tag values can be up to 250 characters in length -func (c *internalClient) LogBatch(ctx context.Context, req *LogBatchRequest, opts ...call.Option) (*LogBatchResponse, error) { - wireReq, err := logBatchRequestToWire(req) +func (c *internalClient) LogBatch(ctx context.Context, req LogBatchRequest, opts ...call.Option) (*LogBatchResponse, error) { + wireReq, err := logBatchRequestToWire(&req) if err != nil { return nil, err } @@ -1441,8 +1452,8 @@ func (c *internalClient) LogBatch(ctx context.Context, req *LogBatchRequest, opt } // Logs inputs, such as datasets and models, to an MLflow Run. -func (c *internalClient) LogInputs(ctx context.Context, req *LogInputsRequest, opts ...call.Option) (*LogInputsResponse, error) { - wireReq, err := logInputsRequestToWire(req) +func (c *internalClient) LogInputs(ctx context.Context, req LogInputsRequest, opts ...call.Option) (*LogInputsResponse, error) { + wireReq, err := logInputsRequestToWire(&req) if err != nil { return nil, err } @@ -1504,8 +1515,8 @@ func (c *internalClient) LogInputs(ctx context.Context, req *LogInputsRequest, o // string value). Examples include hyperparameters used for ML model training. A // param can be logged only once for a logged model, and attempting to overwrite // an existing param with a different value will result in an error -func (c *internalClient) LogLoggedModelParams(ctx context.Context, req *LogLoggedModelParamsRequest, opts ...call.Option) (*LogLoggedModelParamsResponse, error) { - wireReq, err := logLoggedModelParamsRequestToWire(req) +func (c *internalClient) LogLoggedModelParams(ctx context.Context, req LogLoggedModelParamsRequest, opts ...call.Option) (*LogLoggedModelParamsResponse, error) { + wireReq, err := logLoggedModelParamsRequestToWire(&req) if err != nil { return nil, err } @@ -1526,7 +1537,11 @@ func (c *internalClient) LogLoggedModelParams(ctx context.Context, req *LogLogge } pb := pathBuilder{} pb.literal("/api/2.0/mlflow/logged-models/") - pb.singleSegment(*req.ModelId) + if req.ModelId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ModelId) + } pb.literal("/params") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1570,8 +1585,8 @@ func (c *internalClient) LogLoggedModelParams(ctx context.Context, req *LogLogge // Log a metric for a run. A metric is a key-value pair (string key, float // value) with an associated timestamp. Examples include the various metrics // that represent ML model accuracy. A metric can be logged multiple times. -func (c *internalClient) LogMetric(ctx context.Context, req *LogMetricRequest, opts ...call.Option) (*LogMetricResponse, error) { - wireReq, err := logMetricRequestToWire(req) +func (c *internalClient) LogMetric(ctx context.Context, req LogMetricRequest, opts ...call.Option) (*LogMetricResponse, error) { + wireReq, err := logMetricRequestToWire(&req) if err != nil { return nil, err } @@ -1634,8 +1649,8 @@ func (c *internalClient) LogMetric(ctx context.Context, req *LogMetricRequest, o // endpoint. // // Log a model to an MLflow Run. -func (c *internalClient) LogModel(ctx context.Context, req *LogModelRequest, opts ...call.Option) (*LogModelResponse, error) { - wireReq, err := logModelRequestToWire(req) +func (c *internalClient) LogModel(ctx context.Context, req LogModelRequest, opts ...call.Option) (*LogModelResponse, error) { + wireReq, err := logModelRequestToWire(&req) if err != nil { return nil, err } @@ -1694,8 +1709,8 @@ func (c *internalClient) LogModel(ctx context.Context, req *LogModelRequest, opt } // Logs outputs, such as models, from an MLflow Run. -func (c *internalClient) LogOutputs(ctx context.Context, req *LogOutputsRequest, opts ...call.Option) (*LogOutputsResponse, error) { - wireReq, err := logOutputsRequestToWire(req) +func (c *internalClient) LogOutputs(ctx context.Context, req LogOutputsRequest, opts ...call.Option) (*LogOutputsResponse, error) { + wireReq, err := logOutputsRequestToWire(&req) if err != nil { return nil, err } @@ -1757,8 +1772,8 @@ func (c *internalClient) LogOutputs(ctx context.Context, req *LogOutputsRequest, // value). Examples include hyperparameters used for ML model training and // constant dates and values used in an ETL pipeline. A param can be logged only // once for a run. -func (c *internalClient) LogParam(ctx context.Context, req *LogParamRequest, opts ...call.Option) (*LogParamResponse, error) { - wireReq, err := logParamRequestToWire(req) +func (c *internalClient) LogParam(ctx context.Context, req LogParamRequest, opts ...call.Option) (*LogParamResponse, error) { + wireReq, err := logParamRequestToWire(&req) if err != nil { return nil, err } @@ -1822,8 +1837,8 @@ func (c *internalClient) LogParam(ctx context.Context, req *LogParamRequest, opt // // Throws `RESOURCE_DOES_NOT_EXIST` if experiment was never created or was // permanently deleted. -func (c *internalClient) RestoreExperiment(ctx context.Context, req *RestoreExperimentRequest, opts ...call.Option) (*RestoreExperimentResponse, error) { - wireReq, err := restoreExperimentRequestToWire(req) +func (c *internalClient) RestoreExperiment(ctx context.Context, req RestoreExperimentRequest, opts ...call.Option) (*RestoreExperimentResponse, error) { + wireReq, err := restoreExperimentRequestToWire(&req) if err != nil { return nil, err } @@ -1886,8 +1901,8 @@ func (c *internalClient) RestoreExperiment(ctx context.Context, req *RestoreExpe // // Throws `RESOURCE_DOES_NOT_EXIST` if the run was never created or was // permanently deleted. -func (c *internalClient) RestoreRun(ctx context.Context, req *RestoreRunRequest, opts ...call.Option) (*RestoreRunResponse, error) { - wireReq, err := restoreRunRequestToWire(req) +func (c *internalClient) RestoreRun(ctx context.Context, req RestoreRunRequest, opts ...call.Option) (*RestoreRunResponse, error) { + wireReq, err := restoreRunRequestToWire(&req) if err != nil { return nil, err } @@ -1948,8 +1963,8 @@ func (c *internalClient) RestoreRun(ctx context.Context, req *RestoreRunRequest, // Bulk restore runs in an experiment that were deleted no earlier than the // specified timestamp. Restores at most max_runs per request. To call this API // from a Databricks Notebook in Python, you can use the client code snippet on -func (c *internalClient) RestoreRuns(ctx context.Context, req *RestoreRunsRequest, opts ...call.Option) (*RestoreRunsResponse, error) { - wireReq, err := restoreRunsRequestToWire(req) +func (c *internalClient) RestoreRuns(ctx context.Context, req RestoreRunsRequest, opts ...call.Option) (*RestoreRunsResponse, error) { + wireReq, err := restoreRunsRequestToWire(&req) if err != nil { return nil, err } @@ -2014,8 +2029,8 @@ func (c *internalClient) RestoreRuns(ctx context.Context, req *RestoreRunsReques } // Searches for experiments that satisfy specified search criteria. -func (c *internalClient) SearchExperiments(ctx context.Context, req *SearchExperimentsRequest, opts ...call.Option) (*SearchExperimentsResponse, error) { - wireReq, err := searchExperimentsRequestToWire(req) +func (c *internalClient) SearchExperiments(ctx context.Context, req SearchExperimentsRequest, opts ...call.Option) (*SearchExperimentsResponse, error) { + wireReq, err := searchExperimentsRequestToWire(&req) if err != nil { return nil, err } @@ -2084,7 +2099,7 @@ func (c *internalClient) SearchExperiments(ctx context.Context, req *SearchExper // // For example: // -// for item, err := range c.SearchExperimentsIter(ctx, &SearchExperimentsRequest{}) { +// for item, err := range c.SearchExperimentsIter(ctx, SearchExperimentsRequest{}) { // if err != nil { // return err // } @@ -2096,16 +2111,13 @@ func (c *internalClient) SearchExperiments(ctx context.Context, req *SearchExper // // Callers who need custom pagination logic should use // SearchExperiments directly. -func (c *internalClient) SearchExperimentsIter(ctx context.Context, req *SearchExperimentsRequest, opts ...call.Option) iter.Seq2[*Experiment, error] { +func (c *internalClient) SearchExperimentsIter(ctx context.Context, req SearchExperimentsRequest, opts ...call.Option) iter.Seq2[*Experiment, error] { return func(yield func(*Experiment, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := SearchExperimentsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.SearchExperiments(ctx, &pageReq, opts...) + resp, err := c.SearchExperiments(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -2124,8 +2136,8 @@ func (c *internalClient) SearchExperimentsIter(ctx context.Context, req *SearchE } // Search for Logged Models that satisfy specified search criteria. -func (c *internalClient) SearchLoggedModels(ctx context.Context, req *SearchLoggedModelsRequest, opts ...call.Option) (*SearchLoggedModelsResponse, error) { - wireReq, err := searchLoggedModelsRequestToWire(req) +func (c *internalClient) SearchLoggedModels(ctx context.Context, req SearchLoggedModelsRequest, opts ...call.Option) (*SearchLoggedModelsResponse, error) { + wireReq, err := searchLoggedModelsRequestToWire(&req) if err != nil { return nil, err } @@ -2192,8 +2204,8 @@ func (c *internalClient) SearchLoggedModels(ctx context.Context, req *SearchLogg // Searches for runs that satisfy expressions. // // Search expressions can use `mlflowMetric` and `mlflowParam` keys. -func (c *internalClient) SearchRuns(ctx context.Context, req *SearchRunsRequest, opts ...call.Option) (*SearchRunsResponse, error) { - wireReq, err := searchRunsRequestToWire(req) +func (c *internalClient) SearchRuns(ctx context.Context, req SearchRunsRequest, opts ...call.Option) (*SearchRunsResponse, error) { + wireReq, err := searchRunsRequestToWire(&req) if err != nil { return nil, err } @@ -2262,7 +2274,7 @@ func (c *internalClient) SearchRuns(ctx context.Context, req *SearchRunsRequest, // // For example: // -// for item, err := range c.SearchRunsIter(ctx, &SearchRunsRequest{}) { +// for item, err := range c.SearchRunsIter(ctx, SearchRunsRequest{}) { // if err != nil { // return err // } @@ -2274,16 +2286,13 @@ func (c *internalClient) SearchRuns(ctx context.Context, req *SearchRunsRequest, // // Callers who need custom pagination logic should use // SearchRuns directly. -func (c *internalClient) SearchRunsIter(ctx context.Context, req *SearchRunsRequest, opts ...call.Option) iter.Seq2[*Run, error] { +func (c *internalClient) SearchRunsIter(ctx context.Context, req SearchRunsRequest, opts ...call.Option) iter.Seq2[*Run, error] { return func(yield func(*Run, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := SearchRunsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.SearchRuns(ctx, &pageReq, opts...) + resp, err := c.SearchRuns(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -2303,8 +2312,8 @@ func (c *internalClient) SearchRunsIter(ctx context.Context, req *SearchRunsRequ // Sets a tag on an experiment. Experiment tags are metadata that can be // updated. -func (c *internalClient) SetExperimentTag(ctx context.Context, req *SetExperimentTagRequest, opts ...call.Option) (*SetExperimentTagResponse, error) { - wireReq, err := setExperimentTagRequestToWire(req) +func (c *internalClient) SetExperimentTag(ctx context.Context, req SetExperimentTagRequest, opts ...call.Option) (*SetExperimentTagResponse, error) { + wireReq, err := setExperimentTagRequestToWire(&req) if err != nil { return nil, err } @@ -2363,8 +2372,8 @@ func (c *internalClient) SetExperimentTag(ctx context.Context, req *SetExperimen } // Set tags for a logged model. -func (c *internalClient) SetLoggedModelTags(ctx context.Context, req *SetLoggedModelTagsRequest, opts ...call.Option) (*SetLoggedModelTagsResponse, error) { - wireReq, err := setLoggedModelTagsRequestToWire(req) +func (c *internalClient) SetLoggedModelTags(ctx context.Context, req SetLoggedModelTagsRequest, opts ...call.Option) (*SetLoggedModelTagsResponse, error) { + wireReq, err := setLoggedModelTagsRequestToWire(&req) if err != nil { return nil, err } @@ -2385,7 +2394,11 @@ func (c *internalClient) SetLoggedModelTags(ctx context.Context, req *SetLoggedM } pb := pathBuilder{} pb.literal("/api/2.0/mlflow/logged-models/") - pb.singleSegment(*req.ModelId) + if req.ModelId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ModelId) + } pb.literal("/tags") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -2428,8 +2441,8 @@ func (c *internalClient) SetLoggedModelTags(ctx context.Context, req *SetLoggedM // Sets a tag on a run. Tags are run metadata that can be updated during a run // and after a run completes. -func (c *internalClient) SetTag(ctx context.Context, req *SetTagRequest, opts ...call.Option) (*SetTagResponse, error) { - wireReq, err := setTagRequestToWire(req) +func (c *internalClient) SetTag(ctx context.Context, req SetTagRequest, opts ...call.Option) (*SetTagResponse, error) { + wireReq, err := setTagRequestToWire(&req) if err != nil { return nil, err } @@ -2488,8 +2501,8 @@ func (c *internalClient) SetTag(ctx context.Context, req *SetTagRequest, opts .. } // Updates experiment metadata. -func (c *internalClient) UpdateExperiment(ctx context.Context, req *UpdateExperimentRequest, opts ...call.Option) (*UpdateExperimentResponse, error) { - wireReq, err := updateExperimentRequestToWire(req) +func (c *internalClient) UpdateExperiment(ctx context.Context, req UpdateExperimentRequest, opts ...call.Option) (*UpdateExperimentResponse, error) { + wireReq, err := updateExperimentRequestToWire(&req) if err != nil { return nil, err } @@ -2548,8 +2561,8 @@ func (c *internalClient) UpdateExperiment(ctx context.Context, req *UpdateExperi } // Updates run metadata. -func (c *internalClient) UpdateRun(ctx context.Context, req *UpdateRunRequest, opts ...call.Option) (*UpdateRunResponse, error) { - wireReq, err := updateRunRequestToWire(req) +func (c *internalClient) UpdateRun(ctx context.Context, req UpdateRunRequest, opts ...call.Option) (*UpdateRunResponse, error) { + wireReq, err := updateRunRequestToWire(&req) if err != nil { return nil, err } diff --git a/experiments/v1/genhelper.go b/experiments/v1/genhelper.go old mode 100755 new mode 100644 index 91058f6..86451d6 --- a/experiments/v1/genhelper.go +++ b/experiments/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/experiments/v1/wire.go b/experiments/v1/wire.go old mode 100755 new mode 100644 index b03a7f9..80b62f1 --- a/experiments/v1/wire.go +++ b/experiments/v1/wire.go @@ -3,9 +3,55 @@ package experiments import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type createExperimentRequestWire struct { Name *string `json:"name,omitempty"` ArtifactLocation *string `json:"artifact_location,omitempty"` @@ -98,7 +144,7 @@ type createRunRequestWire struct { ExperimentId *string `json:"experiment_id,omitempty"` UserId *string `json:"user_id,omitempty"` RunName *string `json:"run_name,omitempty"` - StartTime *int64 `json:"start_time,omitempty"` + StartTime *wireInt64 `json:"start_time,omitempty"` Tags []runTagWire `json:"tags,omitempty"` } @@ -106,6 +152,10 @@ func createRunRequestToWire(v *CreateRunRequest) (*createRunRequestWire, error) if v == nil { return nil, nil } + startTimeWireValue, err := int64ToWire(v.StartTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateRunRequest.StartTime", err) + } tagsWireValue, err := convertSlice(v.Tags, runTagToWire) if err != nil { return nil, fmt.Errorf("%s: %w", "CreateRunRequest.Tags", err) @@ -114,7 +164,7 @@ func createRunRequestToWire(v *CreateRunRequest) (*createRunRequestWire, error) ExperimentId: v.ExperimentId, UserId: v.UserId, RunName: v.RunName, - StartTime: v.StartTime, + StartTime: startTimeWireValue, Tags: tagsWireValue, }, nil } @@ -241,18 +291,22 @@ func deleteRunRequestToWire(v *DeleteRunRequest) (*deleteRunRequestWire, error) } type deleteRunsRequestWire struct { - ExperimentId *string `json:"experiment_id,omitempty"` - MaxTimestampMillis *int64 `json:"max_timestamp_millis,omitempty"` - MaxRuns *int `json:"max_runs,omitempty"` + ExperimentId *string `json:"experiment_id,omitempty"` + MaxTimestampMillis *wireInt64 `json:"max_timestamp_millis,omitempty"` + MaxRuns *int `json:"max_runs,omitempty"` } func deleteRunsRequestToWire(v *DeleteRunsRequest) (*deleteRunsRequestWire, error) { if v == nil { return nil, nil } + maxTimestampMillisWireValue, err := int64ToWire(v.MaxTimestampMillis) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DeleteRunsRequest.MaxTimestampMillis", err) + } return &deleteRunsRequestWire{ ExperimentId: v.ExperimentId, - MaxTimestampMillis: v.MaxTimestampMillis, + MaxTimestampMillis: maxTimestampMillisWireValue, MaxRuns: v.MaxRuns, }, nil } @@ -290,8 +344,8 @@ type experimentWire struct { Name *string `json:"name,omitempty"` ArtifactLocation *string `json:"artifact_location,omitempty"` LifecycleStage *string `json:"lifecycle_stage,omitempty"` - LastUpdateTime *int64 `json:"last_update_time,omitempty"` - CreationTime *int64 `json:"creation_time,omitempty"` + LastUpdateTime *wireInt64 `json:"last_update_time,omitempty"` + CreationTime *wireInt64 `json:"creation_time,omitempty"` Tags []experimentTagWire `json:"tags,omitempty"` TraceLocation *experimentTraceLocationWire `json:"trace_location,omitempty"` } @@ -300,6 +354,14 @@ func experimentFromWire(w *experimentWire) (*Experiment, error) { if w == nil { return nil, nil } + lastUpdateTimePublicValue, err := int64FromWire(w.LastUpdateTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Experiment.LastUpdateTime", err) + } + creationTimePublicValue, err := int64FromWire(w.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Experiment.CreationTime", err) + } tagsPublicValue, err := convertSlice(w.Tags, experimentTagFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "Experiment.Tags", err) @@ -313,8 +375,8 @@ func experimentFromWire(w *experimentWire) (*Experiment, error) { Name: w.Name, ArtifactLocation: w.ArtifactLocation, LifecycleStage: w.LifecycleStage, - LastUpdateTime: w.LastUpdateTime, - CreationTime: w.CreationTime, + LastUpdateTime: lastUpdateTimePublicValue, + CreationTime: creationTimePublicValue, Tags: tagsPublicValue, TraceLocation: traceLocationPublicValue, }, nil @@ -398,19 +460,23 @@ func experimentTraceLocationFromWire(w *experimentTraceLocationWire) (*Experimen } type fileInfoWire struct { - Path *string `json:"path,omitempty"` - IsDir *bool `json:"is_dir,omitempty"` - FileSize *int64 `json:"file_size,omitempty"` + Path *string `json:"path,omitempty"` + IsDir *bool `json:"is_dir,omitempty"` + FileSize *wireInt64 `json:"file_size,omitempty"` } func fileInfoFromWire(w *fileInfoWire) (*FileInfo, error) { if w == nil { return nil, nil } + fileSizePublicValue, err := int64FromWire(w.FileSize) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FileInfo.FileSize", err) + } return &FileInfo{ Path: w.Path, IsDir: w.IsDir, - FileSize: w.FileSize, + FileSize: fileSizePublicValue, }, nil } @@ -646,18 +712,22 @@ func listArtifactsResponseFromWire(w *listArtifactsResponseWire) (*ListArtifacts } type listExperimentsRequestWire struct { - ViewType ViewType `json:"view_type,omitempty"` - MaxResults *int64 `json:"max_results,omitempty"` - PageToken *string `json:"page_token,omitempty"` + ViewType ViewType `json:"view_type,omitempty"` + MaxResults *wireInt64 `json:"max_results,omitempty"` + PageToken *string `json:"page_token,omitempty"` } func listExperimentsRequestToWire(v *ListExperimentsRequest) (*listExperimentsRequestWire, error) { if v == nil { return nil, nil } + maxResultsWireValue, err := int64ToWire(v.MaxResults) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListExperimentsRequest.MaxResults", err) + } return &listExperimentsRequestWire{ ViewType: v.ViewType, - MaxResults: v.MaxResults, + MaxResults: maxResultsWireValue, PageToken: v.PageToken, }, nil } @@ -778,28 +848,36 @@ func logLoggedModelParamsRequestToWire(v *LogLoggedModelParamsRequest) (*logLogg } type logMetricRequestWire struct { - RunId *string `json:"run_id,omitempty"` - RunUuid *string `json:"run_uuid,omitempty"` - Key *string `json:"key,omitempty"` - Value *float64 `json:"value,omitempty"` - Timestamp *int64 `json:"timestamp,omitempty"` - Step *int64 `json:"step,omitempty"` - ModelId *string `json:"model_id,omitempty"` - DatasetName *string `json:"dataset_name,omitempty"` - DatasetDigest *string `json:"dataset_digest,omitempty"` + RunId *string `json:"run_id,omitempty"` + RunUuid *string `json:"run_uuid,omitempty"` + Key *string `json:"key,omitempty"` + Value *float64 `json:"value,omitempty"` + Timestamp *wireInt64 `json:"timestamp,omitempty"` + Step *wireInt64 `json:"step,omitempty"` + ModelId *string `json:"model_id,omitempty"` + DatasetName *string `json:"dataset_name,omitempty"` + DatasetDigest *string `json:"dataset_digest,omitempty"` } func logMetricRequestToWire(v *LogMetricRequest) (*logMetricRequestWire, error) { if v == nil { return nil, nil } + timestampWireValue, err := int64ToWire(v.Timestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "LogMetricRequest.Timestamp", err) + } + stepWireValue, err := int64ToWire(v.Step) + if err != nil { + return nil, fmt.Errorf("%s: %w", "LogMetricRequest.Step", err) + } return &logMetricRequestWire{ RunId: v.RunId, RunUuid: v.RunUuid, Key: v.Key, Value: v.Value, - Timestamp: v.Timestamp, - Step: v.Step, + Timestamp: timestampWireValue, + Step: stepWireValue, ModelId: v.ModelId, DatasetName: v.DatasetName, DatasetDigest: v.DatasetDigest, @@ -909,11 +987,11 @@ type loggedModelInfoWire struct { ModelId *string `json:"model_id,omitempty"` ExperimentId *string `json:"experiment_id,omitempty"` Name *string `json:"name,omitempty"` - CreationTimestampMs *int64 `json:"creation_timestamp_ms,omitempty"` - LastUpdatedTimestampMs *int64 `json:"last_updated_timestamp_ms,omitempty"` + CreationTimestampMs *wireInt64 `json:"creation_timestamp_ms,omitempty"` + LastUpdatedTimestampMs *wireInt64 `json:"last_updated_timestamp_ms,omitempty"` ArtifactUri *string `json:"artifact_uri,omitempty"` Status LoggedModelStatus `json:"status,omitempty"` - CreatorId *int64 `json:"creator_id,omitempty"` + CreatorId *wireInt64 `json:"creator_id,omitempty"` ModelType *string `json:"model_type,omitempty"` SourceRunId *string `json:"source_run_id,omitempty"` StatusMessage *string `json:"status_message,omitempty"` @@ -924,6 +1002,18 @@ func loggedModelInfoFromWire(w *loggedModelInfoWire) (*LoggedModelInfo, error) { if w == nil { return nil, nil } + creationTimestampMsPublicValue, err := int64FromWire(w.CreationTimestampMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "LoggedModelInfo.CreationTimestampMs", err) + } + lastUpdatedTimestampMsPublicValue, err := int64FromWire(w.LastUpdatedTimestampMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "LoggedModelInfo.LastUpdatedTimestampMs", err) + } + creatorIdPublicValue, err := int64FromWire(w.CreatorId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "LoggedModelInfo.CreatorId", err) + } tagsPublicValue, err := convertSlice(w.Tags, loggedModelTagFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "LoggedModelInfo.Tags", err) @@ -932,11 +1022,11 @@ func loggedModelInfoFromWire(w *loggedModelInfoWire) (*LoggedModelInfo, error) { ModelId: w.ModelId, ExperimentId: w.ExperimentId, Name: w.Name, - CreationTimestampMs: w.CreationTimestampMs, - LastUpdatedTimestampMs: w.LastUpdatedTimestampMs, + CreationTimestampMs: creationTimestampMsPublicValue, + LastUpdatedTimestampMs: lastUpdatedTimestampMsPublicValue, ArtifactUri: w.ArtifactUri, Status: w.Status, - CreatorId: w.CreatorId, + CreatorId: creatorIdPublicValue, ModelType: w.ModelType, SourceRunId: w.SourceRunId, StatusMessage: w.StatusMessage, @@ -995,25 +1085,33 @@ func loggedModelTagFromWire(w *loggedModelTagWire) (*LoggedModelTag, error) { } type metricWire struct { - Key *string `json:"key,omitempty"` - Value *float64 `json:"value,omitempty"` - Timestamp *int64 `json:"timestamp,omitempty"` - Step *int64 `json:"step,omitempty"` - DatasetName *string `json:"dataset_name,omitempty"` - DatasetDigest *string `json:"dataset_digest,omitempty"` - ModelId *string `json:"model_id,omitempty"` - RunId *string `json:"run_id,omitempty"` + Key *string `json:"key,omitempty"` + Value *float64 `json:"value,omitempty"` + Timestamp *wireInt64 `json:"timestamp,omitempty"` + Step *wireInt64 `json:"step,omitempty"` + DatasetName *string `json:"dataset_name,omitempty"` + DatasetDigest *string `json:"dataset_digest,omitempty"` + ModelId *string `json:"model_id,omitempty"` + RunId *string `json:"run_id,omitempty"` } func metricToWire(v *Metric) (*metricWire, error) { if v == nil { return nil, nil } + timestampWireValue, err := int64ToWire(v.Timestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Metric.Timestamp", err) + } + stepWireValue, err := int64ToWire(v.Step) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Metric.Step", err) + } return &metricWire{ Key: v.Key, Value: v.Value, - Timestamp: v.Timestamp, - Step: v.Step, + Timestamp: timestampWireValue, + Step: stepWireValue, DatasetName: v.DatasetName, DatasetDigest: v.DatasetDigest, ModelId: v.ModelId, @@ -1025,11 +1123,19 @@ func metricFromWire(w *metricWire) (*Metric, error) { if w == nil { return nil, nil } + timestampPublicValue, err := int64FromWire(w.Timestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Metric.Timestamp", err) + } + stepPublicValue, err := int64FromWire(w.Step) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Metric.Step", err) + } return &Metric{ Key: w.Key, Value: w.Value, - Timestamp: w.Timestamp, - Step: w.Step, + Timestamp: timestampPublicValue, + Step: stepPublicValue, DatasetName: w.DatasetName, DatasetDigest: w.DatasetDigest, ModelId: w.ModelId, @@ -1060,17 +1166,21 @@ func modelInputFromWire(w *modelInputWire) (*ModelInput, error) { } type modelOutputWire struct { - ModelId *string `json:"model_id,omitempty"` - Step *int64 `json:"step,omitempty"` + ModelId *string `json:"model_id,omitempty"` + Step *wireInt64 `json:"step,omitempty"` } func modelOutputToWire(v *ModelOutput) (*modelOutputWire, error) { if v == nil { return nil, nil } + stepWireValue, err := int64ToWire(v.Step) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ModelOutput.Step", err) + } return &modelOutputWire{ ModelId: v.ModelId, - Step: v.Step, + Step: stepWireValue, }, nil } @@ -1126,18 +1236,22 @@ func restoreRunRequestToWire(v *RestoreRunRequest) (*restoreRunRequestWire, erro } type restoreRunsRequestWire struct { - ExperimentId *string `json:"experiment_id,omitempty"` - MinTimestampMillis *int64 `json:"min_timestamp_millis,omitempty"` - MaxRuns *int `json:"max_runs,omitempty"` + ExperimentId *string `json:"experiment_id,omitempty"` + MinTimestampMillis *wireInt64 `json:"min_timestamp_millis,omitempty"` + MaxRuns *int `json:"max_runs,omitempty"` } func restoreRunsRequestToWire(v *RestoreRunsRequest) (*restoreRunsRequestWire, error) { if v == nil { return nil, nil } + minTimestampMillisWireValue, err := int64ToWire(v.MinTimestampMillis) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RestoreRunsRequest.MinTimestampMillis", err) + } return &restoreRunsRequestWire{ ExperimentId: v.ExperimentId, - MinTimestampMillis: v.MinTimestampMillis, + MinTimestampMillis: minTimestampMillisWireValue, MaxRuns: v.MaxRuns, }, nil } @@ -1214,22 +1328,30 @@ func runDataFromWire(w *runDataWire) (*RunData, error) { } type runInfoWire struct { - RunId *string `json:"run_id,omitempty"` - RunUuid *string `json:"run_uuid,omitempty"` - ExperimentId *string `json:"experiment_id,omitempty"` - RunName *string `json:"run_name,omitempty"` - UserId *string `json:"user_id,omitempty"` - Status RunStatus `json:"status,omitempty"` - StartTime *int64 `json:"start_time,omitempty"` - EndTime *int64 `json:"end_time,omitempty"` - ArtifactUri *string `json:"artifact_uri,omitempty"` - LifecycleStage *string `json:"lifecycle_stage,omitempty"` + RunId *string `json:"run_id,omitempty"` + RunUuid *string `json:"run_uuid,omitempty"` + ExperimentId *string `json:"experiment_id,omitempty"` + RunName *string `json:"run_name,omitempty"` + UserId *string `json:"user_id,omitempty"` + Status RunStatus `json:"status,omitempty"` + StartTime *wireInt64 `json:"start_time,omitempty"` + EndTime *wireInt64 `json:"end_time,omitempty"` + ArtifactUri *string `json:"artifact_uri,omitempty"` + LifecycleStage *string `json:"lifecycle_stage,omitempty"` } func runInfoFromWire(w *runInfoWire) (*RunInfo, error) { if w == nil { return nil, nil } + startTimePublicValue, err := int64FromWire(w.StartTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RunInfo.StartTime", err) + } + endTimePublicValue, err := int64FromWire(w.EndTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RunInfo.EndTime", err) + } return &RunInfo{ RunId: w.RunId, RunUuid: w.RunUuid, @@ -1237,8 +1359,8 @@ func runInfoFromWire(w *runInfoWire) (*RunInfo, error) { RunName: w.RunName, UserId: w.UserId, Status: w.Status, - StartTime: w.StartTime, - EndTime: w.EndTime, + StartTime: startTimePublicValue, + EndTime: endTimePublicValue, ArtifactUri: w.ArtifactUri, LifecycleStage: w.LifecycleStage, }, nil @@ -1293,19 +1415,23 @@ func runTagFromWire(w *runTagWire) (*RunTag, error) { } type searchExperimentsRequestWire struct { - MaxResults *int64 `json:"max_results,omitempty"` - PageToken *string `json:"page_token,omitempty"` - Filter *string `json:"filter,omitempty"` - OrderBy []string `json:"order_by,omitempty"` - ViewType ViewType `json:"view_type,omitempty"` + MaxResults *wireInt64 `json:"max_results,omitempty"` + PageToken *string `json:"page_token,omitempty"` + Filter *string `json:"filter,omitempty"` + OrderBy []string `json:"order_by,omitempty"` + ViewType ViewType `json:"view_type,omitempty"` } func searchExperimentsRequestToWire(v *SearchExperimentsRequest) (*searchExperimentsRequestWire, error) { if v == nil { return nil, nil } + maxResultsWireValue, err := int64ToWire(v.MaxResults) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SearchExperimentsRequest.MaxResults", err) + } return &searchExperimentsRequestWire{ - MaxResults: v.MaxResults, + MaxResults: maxResultsWireValue, PageToken: v.PageToken, Filter: v.Filter, OrderBy: v.OrderBy, @@ -1560,22 +1686,26 @@ func updateExperimentRequestToWire(v *UpdateExperimentRequest) (*updateExperimen } type updateRunRequestWire struct { - RunId *string `json:"run_id,omitempty"` - RunUuid *string `json:"run_uuid,omitempty"` - Status RunStatus `json:"status,omitempty"` - EndTime *int64 `json:"end_time,omitempty"` - RunName *string `json:"run_name,omitempty"` + RunId *string `json:"run_id,omitempty"` + RunUuid *string `json:"run_uuid,omitempty"` + Status RunStatus `json:"status,omitempty"` + EndTime *wireInt64 `json:"end_time,omitempty"` + RunName *string `json:"run_name,omitempty"` } func updateRunRequestToWire(v *UpdateRunRequest) (*updateRunRequestWire, error) { if v == nil { return nil, nil } + endTimeWireValue, err := int64ToWire(v.EndTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateRunRequest.EndTime", err) + } return &updateRunRequestWire{ RunId: v.RunId, RunUuid: v.RunUuid, Status: v.Status, - EndTime: v.EndTime, + EndTime: endTimeWireValue, RunName: v.RunName, }, nil } diff --git a/features/CHANGELOG.md b/features/CHANGELOG.md index 6224c04..19f237c 100644 --- a/features/CHANGELOG.md +++ b/features/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/features/go.mod b/features/go.mod index 37f51b1..df108ef 100644 --- a/features/go.mod +++ b/features/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/features/internal/version.go b/features/internal/version.go index 20dafa2..aaa492b 100644 --- a/features/internal/version.go +++ b/features/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-features" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/features/v1/client.go b/features/v1/client.go old mode 100755 new mode 100644 index 389f7ea..815e0df --- a/features/v1/client.go +++ b/features/v1/client.go @@ -6,6 +6,7 @@ import ( "bytes" "context" "encoding/json" + "fmt" "iter" "log/slog" "net/http" @@ -18,6 +19,7 @@ import ( "github.com/databricks/sdk-go/options/call" "github.com/databricks/sdk-go/options/client" "github.com/databricks/sdk-go/options/internaloptions" + "github.com/databricks/sdk-go/options/lro" ) type Client struct { @@ -74,9 +76,184 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { }, nil } +// Backfill features. +func (c *internalClient) backfillFeaturesBase(ctx context.Context, req BackfillFeaturesRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := backfillFeaturesRequestToWire(&req) + if err != nil { + return nil, err + } + if wireReq.RequestId == nil || *wireReq.RequestId == "" { + wireReq.RequestId = new(generateRequestID()) + } + body, err := json.Marshal(wireReq) + if err != nil { + return nil, err + } + + headers := http.Header{} + headers.Set("Content-Type", "application/json") + if c.workspaceID != "" { + headers.Set("X-Databricks-Workspace-Id", c.workspaceID) + } + + baseURL, err := url.Parse(c.host) + if err != nil { + return nil, err + } + baseURL.Path = "/api/2.0/feature-engineering/features:backfill" + queryParams := url.Values{} + baseURL.RawQuery = queryParams.Encode() + urlStr := baseURL.String() + + var resp *Operation + + call := func(ctx context.Context) error { + httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ + Method: "POST", + URL: urlStr, + Credentials: c.credentials, + UserAgent: c.userAgent, + Headers: headers, + Body: bytes.NewBuffer(body), + }) + if err != nil { + return err + } + + respBody, _, err := executeHTTPCall(httpCallOptions{ + req: httpReq, + client: c.httpClient, + logger: c.logger, + }) + if err != nil { + return err + } + var wireResp operationWire + if err := json.Unmarshal(respBody, &wireResp); err != nil { + return err + } + resp, err = operationFromWire(&wireResp) + if err != nil { + return err + } + return nil + } + + if err := executeCall(ctx, call, opts); err != nil { + return nil, err + } + return resp, nil +} + +// Backfill features. +func (c *internalClient) BackfillFeatures(ctx context.Context, req BackfillFeaturesRequest, opts ...call.Option) (*BackfillFeaturesOperation, error) { + operation, err := c.backfillFeaturesBase(ctx, req, opts...) + if err != nil { + return nil, err + } + if err := validateOperationName(operation.Name); err != nil { + return nil, err + } + return &BackfillFeaturesOperation{ + operation: operation, + getOperation: c.getOperation, + cancelOperation: c.cancelOperation, + }, nil +} + +// BackfillFeaturesOperation tracks the state of the long-running operation started by BackfillFeatures. +type BackfillFeaturesOperation struct { + operation *Operation + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) + cancelOperation func(context.Context, CancelOperationRequest, ...call.Option) error +} + +// Name returns the server-assigned operation name. +func (o *BackfillFeaturesOperation) Name() *string { + return o.operation.Name +} + +// Metadata returns metadata associated with the operation. +func (o *BackfillFeaturesOperation) Metadata() (*BackfillOperationMetadata, error) { + if len(o.operation.Metadata) == 0 || bytes.Equal(bytes.TrimSpace(o.operation.Metadata), []byte("null")) { + return nil, nil + } + var metadata backfillOperationMetadataWire + if err := json.Unmarshal(o.operation.Metadata, &metadata); err != nil { + return nil, fmt.Errorf("decode operation metadata: %w", err) + } + converted, err := backfillOperationMetadataFromWire(&metadata) + if err != nil { + return nil, err + } + return converted, nil +} + +// Done refreshes the operation and reports whether it has completed. +func (o *BackfillFeaturesOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) + if err != nil { + return false, err + } + if err := validateOperationName(operation.Name); err != nil { + return false, err + } + o.operation = operation + if operation.Done == nil { + return false, fmt.Errorf("invalid operation response: missing done field") + } + return *operation.Done, nil +} + +// Wait polls the operation until it completes. +func (o *BackfillFeaturesOperation) Wait(ctx context.Context, opts ...lro.Option) (*BackfillFeaturesResponse, error) { + var result *BackfillFeaturesResponse + poll := func(ctx context.Context) error { + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) + if err != nil { + return err + } + if err := validateOperationName(operation.Name); err != nil { + return err + } + o.operation = operation + if operation.Done == nil { + return fmt.Errorf("invalid operation response: missing done field") + } + if !*operation.Done { + return errOperationStillRunning + } + if operationError, ok := operation.Result.(*Operation_Result_Error); ok && operationError != nil { + return fmt.Errorf("operation failed: %w", &operationError.Error) + } + operationResponse, ok := operation.Result.(*Operation_Result_Response) + if !ok || operationResponse == nil || len(operationResponse.Response) == 0 || bytes.Equal(bytes.TrimSpace(operationResponse.Response), []byte("null")) { + return fmt.Errorf("operation completed without a response") + } + var response backfillFeaturesResponseWire + if err := json.Unmarshal(operationResponse.Response, &response); err != nil { + return fmt.Errorf("decode operation response: %w", err) + } + result, err = backfillFeaturesResponseFromWire(&response) + if err != nil { + return err + } + return nil + } + if err := executeWait(ctx, poll, opts...); err != nil { + return nil, err + } + return result, nil +} + +// Cancel starts asynchronous cancellation of the operation. +func (o *BackfillFeaturesOperation) Cancel(ctx context.Context, opts ...call.Option) error { + return o.cancelOperation(ctx, CancelOperationRequest{Name: o.operation.Name}, opts...) +} + // Batch create materialized features. -func (c *internalClient) BatchCreateMaterializedFeatures(ctx context.Context, req *BatchCreateMaterializedFeaturesRequest, opts ...call.Option) (*BatchCreateMaterializedFeaturesResponse, error) { - wireReq, err := batchCreateMaterializedFeaturesRequestToWire(req) +func (c *internalClient) BatchCreateMaterializedFeatures(ctx context.Context, req BatchCreateMaterializedFeaturesRequest, opts ...call.Option) (*BatchCreateMaterializedFeaturesResponse, error) { + wireReq, err := batchCreateMaterializedFeaturesRequestToWire(&req) if err != nil { return nil, err } @@ -140,9 +317,74 @@ func (c *internalClient) BatchCreateMaterializedFeatures(ctx context.Context, re return resp, nil } +// Cancel an operation. +func (c *internalClient) cancelOperation(ctx context.Context, req CancelOperationRequest, opts ...call.Option) error { + wireReq, err := cancelOperationRequestToWire(&req) + if err != nil { + return err + } + body, err := json.Marshal(wireReq) + if err != nil { + return err + } + + headers := http.Header{} + headers.Set("Content-Type", "application/json") + if c.workspaceID != "" { + headers.Set("X-Databricks-Workspace-Id", c.workspaceID) + } + + baseURL, err := url.Parse(c.host) + if err != nil { + return err + } + pb := pathBuilder{} + pb.literal("/api/2.0/feature-engineering/") + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } + pb.literal(":cancel") + baseURL.Path, baseURL.RawPath = pb.build() + queryParams := url.Values{} + baseURL.RawQuery = queryParams.Encode() + urlStr := baseURL.String() + + call := func(ctx context.Context) error { + httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ + Method: "POST", + URL: urlStr, + Credentials: c.credentials, + UserAgent: c.userAgent, + Headers: headers, + Body: bytes.NewBuffer(body), + }) + if err != nil { + return err + } + + respBody, _, err := executeHTTPCall(httpCallOptions{ + req: httpReq, + client: c.httpClient, + logger: c.logger, + }) + if err != nil { + return err + } + _ = respBody + return nil + } + + if err := executeCall(ctx, call, opts); err != nil { + return err + } + return nil +} + // Create a Feature. -func (c *internalClient) CreateFeature(ctx context.Context, req *CreateFeatureRequest, opts ...call.Option) (*Feature, error) { - wireReq, err := createFeatureRequestToWire(req) +func (c *internalClient) CreateFeature(ctx context.Context, req CreateFeatureRequest, opts ...call.Option) (*Feature, error) { + wireReq, err := createFeatureRequestToWire(&req) if err != nil { return nil, err } @@ -209,8 +451,8 @@ func (c *internalClient) CreateFeature(ctx context.Context, req *CreateFeatureRe // Create a Kafka config. During PrPr, Kafka configs can be read and used when // creating features under the entire metastore. Only the creator of the Kafka // config can delete it. -func (c *internalClient) CreateKafkaConfig(ctx context.Context, req *CreateKafkaConfigRequest, opts ...call.Option) (*KafkaConfig, error) { - wireReq, err := createKafkaConfigRequestToWire(req) +func (c *internalClient) CreateKafkaConfig(ctx context.Context, req CreateKafkaConfigRequest, opts ...call.Option) (*KafkaConfig, error) { + wireReq, err := createKafkaConfigRequestToWire(&req) if err != nil { return nil, err } @@ -275,8 +517,8 @@ func (c *internalClient) CreateKafkaConfig(ctx context.Context, req *CreateKafka } // Create a materialized feature. -func (c *internalClient) CreateMaterializedFeature(ctx context.Context, req *CreateMaterializedFeatureRequest, opts ...call.Option) (*MaterializedFeature, error) { - wireReq, err := createMaterializedFeatureRequestToWire(req) +func (c *internalClient) CreateMaterializedFeature(ctx context.Context, req CreateMaterializedFeatureRequest, opts ...call.Option) (*MaterializedFeature, error) { + wireReq, err := createMaterializedFeatureRequestToWire(&req) if err != nil { return nil, err } @@ -342,8 +584,8 @@ func (c *internalClient) CreateMaterializedFeature(ctx context.Context, req *Cre // Create a Stream, a governed UC entity representing an external streaming data // source. -func (c *internalClient) CreateStream(ctx context.Context, req *CreateStreamRequest, opts ...call.Option) (*Stream, error) { - wireReq, err := createStreamRequestToWire(req) +func (c *internalClient) CreateStream(ctx context.Context, req CreateStreamRequest, opts ...call.Option) (*Stream, error) { + wireReq, err := createStreamRequestToWire(&req) if err != nil { return nil, err } @@ -408,7 +650,7 @@ func (c *internalClient) CreateStream(ctx context.Context, req *CreateStreamRequ } // Delete a Feature. -func (c *internalClient) DeleteFeature(ctx context.Context, req *DeleteFeatureRequest, opts ...call.Option) error { +func (c *internalClient) DeleteFeature(ctx context.Context, req DeleteFeatureRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -422,7 +664,11 @@ func (c *internalClient) DeleteFeature(ctx context.Context, req *DeleteFeatureRe } pb := pathBuilder{} pb.literal("/api/2.0/feature-engineering/features/") - pb.singleSegment(*req.FullName) + if req.FullName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullName) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -461,7 +707,7 @@ func (c *internalClient) DeleteFeature(ctx context.Context, req *DeleteFeatureRe // Delete a Kafka config. During PrPr, Kafka configs can be read and used when // creating features under the entire metastore. Only the creator of the Kafka // config can delete it. -func (c *internalClient) DeleteKafkaConfig(ctx context.Context, req *DeleteKafkaConfigRequest, opts ...call.Option) error { +func (c *internalClient) DeleteKafkaConfig(ctx context.Context, req DeleteKafkaConfigRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -475,7 +721,11 @@ func (c *internalClient) DeleteKafkaConfig(ctx context.Context, req *DeleteKafka } pb := pathBuilder{} pb.literal("/api/2.0/feature-engineering/features/kafka-configs/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -512,7 +762,7 @@ func (c *internalClient) DeleteKafkaConfig(ctx context.Context, req *DeleteKafka } // Delete a materialized feature. -func (c *internalClient) DeleteMaterializedFeature(ctx context.Context, req *DeleteMaterializedFeatureRequest, opts ...call.Option) error { +func (c *internalClient) DeleteMaterializedFeature(ctx context.Context, req DeleteMaterializedFeatureRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -526,7 +776,11 @@ func (c *internalClient) DeleteMaterializedFeature(ctx context.Context, req *Del } pb := pathBuilder{} pb.literal("/api/2.0/feature-engineering/materialized-features/") - pb.singleSegment(*req.MaterializedFeatureId) + if req.MaterializedFeatureId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MaterializedFeatureId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -563,7 +817,7 @@ func (c *internalClient) DeleteMaterializedFeature(ctx context.Context, req *Del } // Delete a Stream by its full three-part name (catalog.schema.stream). -func (c *internalClient) DeleteStream(ctx context.Context, req *DeleteStreamRequest, opts ...call.Option) error { +func (c *internalClient) DeleteStream(ctx context.Context, req DeleteStreamRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -577,7 +831,11 @@ func (c *internalClient) DeleteStream(ctx context.Context, req *DeleteStreamRequ } pb := pathBuilder{} pb.literal("/api/2.0/feature-engineering/streams/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -614,7 +872,7 @@ func (c *internalClient) DeleteStream(ctx context.Context, req *DeleteStreamRequ } // Get a Feature. -func (c *internalClient) GetFeature(ctx context.Context, req *GetFeatureRequest, opts ...call.Option) (*Feature, error) { +func (c *internalClient) GetFeature(ctx context.Context, req GetFeatureRequest, opts ...call.Option) (*Feature, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -628,7 +886,11 @@ func (c *internalClient) GetFeature(ctx context.Context, req *GetFeatureRequest, } pb := pathBuilder{} pb.literal("/api/2.0/feature-engineering/features/") - pb.singleSegment(*req.FullName) + if req.FullName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullName) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -676,7 +938,7 @@ func (c *internalClient) GetFeature(ctx context.Context, req *GetFeatureRequest, // Get a Kafka config. During PrPr, Kafka configs can be read and used when // creating features under the entire metastore. Only the creator of the Kafka // config can delete it. -func (c *internalClient) GetKafkaConfig(ctx context.Context, req *GetKafkaConfigRequest, opts ...call.Option) (*KafkaConfig, error) { +func (c *internalClient) GetKafkaConfig(ctx context.Context, req GetKafkaConfigRequest, opts ...call.Option) (*KafkaConfig, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -690,7 +952,11 @@ func (c *internalClient) GetKafkaConfig(ctx context.Context, req *GetKafkaConfig } pb := pathBuilder{} pb.literal("/api/2.0/feature-engineering/features/kafka-configs/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -736,7 +1002,7 @@ func (c *internalClient) GetKafkaConfig(ctx context.Context, req *GetKafkaConfig } // Get a materialized feature. -func (c *internalClient) GetMaterializedFeature(ctx context.Context, req *GetMaterializedFeatureRequest, opts ...call.Option) (*MaterializedFeature, error) { +func (c *internalClient) GetMaterializedFeature(ctx context.Context, req GetMaterializedFeatureRequest, opts ...call.Option) (*MaterializedFeature, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -750,7 +1016,11 @@ func (c *internalClient) GetMaterializedFeature(ctx context.Context, req *GetMat } pb := pathBuilder{} pb.literal("/api/2.0/feature-engineering/materialized-features/") - pb.singleSegment(*req.MaterializedFeatureId) + if req.MaterializedFeatureId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MaterializedFeatureId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -795,8 +1065,72 @@ func (c *internalClient) GetMaterializedFeature(ctx context.Context, req *GetMat return resp, nil } +// Get an operation. +func (c *internalClient) getOperation(ctx context.Context, req GetOperationRequest, opts ...call.Option) (*Operation, error) { + + headers := http.Header{} + headers.Set("Content-Type", "application/json") + if c.workspaceID != "" { + headers.Set("X-Databricks-Workspace-Id", c.workspaceID) + } + + baseURL, err := url.Parse(c.host) + if err != nil { + return nil, err + } + pb := pathBuilder{} + pb.literal("/api/2.0/feature-engineering/") + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } + baseURL.Path, baseURL.RawPath = pb.build() + queryParams := url.Values{} + baseURL.RawQuery = queryParams.Encode() + urlStr := baseURL.String() + + var resp *Operation + + call := func(ctx context.Context) error { + httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ + Method: "GET", + URL: urlStr, + Credentials: c.credentials, + UserAgent: c.userAgent, + Headers: headers, + }) + if err != nil { + return err + } + + respBody, _, err := executeHTTPCall(httpCallOptions{ + req: httpReq, + client: c.httpClient, + logger: c.logger, + }) + if err != nil { + return err + } + var wireResp operationWire + if err := json.Unmarshal(respBody, &wireResp); err != nil { + return err + } + resp, err = operationFromWire(&wireResp) + if err != nil { + return err + } + return nil + } + + if err := executeCall(ctx, call, opts); err != nil { + return nil, err + } + return resp, nil +} + // Get a Stream by its full three-part name (catalog.schema.stream). -func (c *internalClient) GetStream(ctx context.Context, req *GetStreamRequest, opts ...call.Option) (*Stream, error) { +func (c *internalClient) GetStream(ctx context.Context, req GetStreamRequest, opts ...call.Option) (*Stream, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -810,7 +1144,11 @@ func (c *internalClient) GetStream(ctx context.Context, req *GetStreamRequest, o } pb := pathBuilder{} pb.literal("/api/2.0/feature-engineering/streams/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -856,8 +1194,8 @@ func (c *internalClient) GetStream(ctx context.Context, req *GetStreamRequest, o } // List Features. -func (c *internalClient) ListFeatures(ctx context.Context, req *ListFeaturesRequest, opts ...call.Option) (*ListFeaturesResponse, error) { - wireReq, err := listFeaturesRequestToWire(req) +func (c *internalClient) ListFeatures(ctx context.Context, req ListFeaturesRequest, opts ...call.Option) (*ListFeaturesResponse, error) { + wireReq, err := listFeaturesRequestToWire(&req) if err != nil { return nil, err } @@ -933,7 +1271,7 @@ func (c *internalClient) ListFeatures(ctx context.Context, req *ListFeaturesRequ // // For example: // -// for item, err := range c.ListFeaturesIter(ctx, &ListFeaturesRequest{}) { +// for item, err := range c.ListFeaturesIter(ctx, ListFeaturesRequest{}) { // if err != nil { // return err // } @@ -945,16 +1283,13 @@ func (c *internalClient) ListFeatures(ctx context.Context, req *ListFeaturesRequ // // Callers who need custom pagination logic should use // ListFeatures directly. -func (c *internalClient) ListFeaturesIter(ctx context.Context, req *ListFeaturesRequest, opts ...call.Option) iter.Seq2[*Feature, error] { +func (c *internalClient) ListFeaturesIter(ctx context.Context, req ListFeaturesRequest, opts ...call.Option) iter.Seq2[*Feature, error] { return func(yield func(*Feature, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListFeaturesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListFeatures(ctx, &pageReq, opts...) + resp, err := c.ListFeatures(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -975,8 +1310,8 @@ func (c *internalClient) ListFeaturesIter(ctx context.Context, req *ListFeatures // List Kafka configs. During PrPr, Kafka configs can be read and used when // creating features under the entire metastore. Only the creator of the Kafka // config can delete it. -func (c *internalClient) ListKafkaConfigs(ctx context.Context, req *ListKafkaConfigsRequest, opts ...call.Option) (*ListKafkaConfigsResponse, error) { - wireReq, err := listKafkaConfigsRequestToWire(req) +func (c *internalClient) ListKafkaConfigs(ctx context.Context, req ListKafkaConfigsRequest, opts ...call.Option) (*ListKafkaConfigsResponse, error) { + wireReq, err := listKafkaConfigsRequestToWire(&req) if err != nil { return nil, err } @@ -1046,7 +1381,7 @@ func (c *internalClient) ListKafkaConfigs(ctx context.Context, req *ListKafkaCon // // For example: // -// for item, err := range c.ListKafkaConfigsIter(ctx, &ListKafkaConfigsRequest{}) { +// for item, err := range c.ListKafkaConfigsIter(ctx, ListKafkaConfigsRequest{}) { // if err != nil { // return err // } @@ -1058,16 +1393,13 @@ func (c *internalClient) ListKafkaConfigs(ctx context.Context, req *ListKafkaCon // // Callers who need custom pagination logic should use // ListKafkaConfigs directly. -func (c *internalClient) ListKafkaConfigsIter(ctx context.Context, req *ListKafkaConfigsRequest, opts ...call.Option) iter.Seq2[*KafkaConfig, error] { +func (c *internalClient) ListKafkaConfigsIter(ctx context.Context, req ListKafkaConfigsRequest, opts ...call.Option) iter.Seq2[*KafkaConfig, error] { return func(yield func(*KafkaConfig, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListKafkaConfigsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListKafkaConfigs(ctx, &pageReq, opts...) + resp, err := c.ListKafkaConfigs(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1086,8 +1418,8 @@ func (c *internalClient) ListKafkaConfigsIter(ctx context.Context, req *ListKafk } // List materialized features. -func (c *internalClient) ListMaterializedFeatures(ctx context.Context, req *ListMaterializedFeaturesRequest, opts ...call.Option) (*ListMaterializedFeaturesResponse, error) { - wireReq, err := listMaterializedFeaturesRequestToWire(req) +func (c *internalClient) ListMaterializedFeatures(ctx context.Context, req ListMaterializedFeaturesRequest, opts ...call.Option) (*ListMaterializedFeaturesResponse, error) { + wireReq, err := listMaterializedFeaturesRequestToWire(&req) if err != nil { return nil, err } @@ -1160,7 +1492,7 @@ func (c *internalClient) ListMaterializedFeatures(ctx context.Context, req *List // // For example: // -// for item, err := range c.ListMaterializedFeaturesIter(ctx, &ListMaterializedFeaturesRequest{}) { +// for item, err := range c.ListMaterializedFeaturesIter(ctx, ListMaterializedFeaturesRequest{}) { // if err != nil { // return err // } @@ -1172,16 +1504,13 @@ func (c *internalClient) ListMaterializedFeatures(ctx context.Context, req *List // // Callers who need custom pagination logic should use // ListMaterializedFeatures directly. -func (c *internalClient) ListMaterializedFeaturesIter(ctx context.Context, req *ListMaterializedFeaturesRequest, opts ...call.Option) iter.Seq2[*MaterializedFeature, error] { +func (c *internalClient) ListMaterializedFeaturesIter(ctx context.Context, req ListMaterializedFeaturesRequest, opts ...call.Option) iter.Seq2[*MaterializedFeature, error] { return func(yield func(*MaterializedFeature, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListMaterializedFeaturesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListMaterializedFeatures(ctx, &pageReq, opts...) + resp, err := c.ListMaterializedFeatures(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1200,8 +1529,8 @@ func (c *internalClient) ListMaterializedFeaturesIter(ctx context.Context, req * } // List Streams under a given catalog.schema parent. -func (c *internalClient) ListStreams(ctx context.Context, req *ListStreamsRequest, opts ...call.Option) (*ListStreamsResponse, error) { - wireReq, err := listStreamsRequestToWire(req) +func (c *internalClient) ListStreams(ctx context.Context, req ListStreamsRequest, opts ...call.Option) (*ListStreamsResponse, error) { + wireReq, err := listStreamsRequestToWire(&req) if err != nil { return nil, err } @@ -1274,7 +1603,7 @@ func (c *internalClient) ListStreams(ctx context.Context, req *ListStreamsReques // // For example: // -// for item, err := range c.ListStreamsIter(ctx, &ListStreamsRequest{}) { +// for item, err := range c.ListStreamsIter(ctx, ListStreamsRequest{}) { // if err != nil { // return err // } @@ -1286,16 +1615,13 @@ func (c *internalClient) ListStreams(ctx context.Context, req *ListStreamsReques // // Callers who need custom pagination logic should use // ListStreams directly. -func (c *internalClient) ListStreamsIter(ctx context.Context, req *ListStreamsRequest, opts ...call.Option) iter.Seq2[*Stream, error] { +func (c *internalClient) ListStreamsIter(ctx context.Context, req ListStreamsRequest, opts ...call.Option) iter.Seq2[*Stream, error] { return func(yield func(*Stream, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListStreamsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListStreams(ctx, &pageReq, opts...) + resp, err := c.ListStreams(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1314,8 +1640,8 @@ func (c *internalClient) ListStreamsIter(ctx context.Context, req *ListStreamsRe } // Update a Feature. -func (c *internalClient) UpdateFeature(ctx context.Context, req *UpdateFeatureRequest, opts ...call.Option) (*Feature, error) { - wireReq, err := updateFeatureRequestToWire(req) +func (c *internalClient) UpdateFeature(ctx context.Context, req UpdateFeatureRequest, opts ...call.Option) (*Feature, error) { + wireReq, err := updateFeatureRequestToWire(&req) if err != nil { return nil, err } @@ -1336,7 +1662,11 @@ func (c *internalClient) UpdateFeature(ctx context.Context, req *UpdateFeatureRe } pb := pathBuilder{} pb.literal("/api/2.0/feature-engineering/features/") - pb.singleSegment(*req.Feature.FullName) + if req.Feature == nil || req.Feature.FullName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Feature.FullName) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -1388,8 +1718,8 @@ func (c *internalClient) UpdateFeature(ctx context.Context, req *UpdateFeatureRe // Update a Kafka config. During PrPr, Kafka configs can be read and used when // creating features under the entire metastore. Only the creator of the Kafka // config can delete it. -func (c *internalClient) UpdateKafkaConfig(ctx context.Context, req *UpdateKafkaConfigRequest, opts ...call.Option) (*KafkaConfig, error) { - wireReq, err := updateKafkaConfigRequestToWire(req) +func (c *internalClient) UpdateKafkaConfig(ctx context.Context, req UpdateKafkaConfigRequest, opts ...call.Option) (*KafkaConfig, error) { + wireReq, err := updateKafkaConfigRequestToWire(&req) if err != nil { return nil, err } @@ -1410,7 +1740,11 @@ func (c *internalClient) UpdateKafkaConfig(ctx context.Context, req *UpdateKafka } pb := pathBuilder{} pb.literal("/api/2.0/feature-engineering/features/kafka-configs/") - pb.singleSegment(*req.KafkaConfig.Name) + if req.KafkaConfig == nil || req.KafkaConfig.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.KafkaConfig.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -1460,8 +1794,8 @@ func (c *internalClient) UpdateKafkaConfig(ctx context.Context, req *UpdateKafka } // Update a materialized feature (pause/resume). -func (c *internalClient) UpdateMaterializedFeature(ctx context.Context, req *UpdateMaterializedFeatureRequest, opts ...call.Option) (*MaterializedFeature, error) { - wireReq, err := updateMaterializedFeatureRequestToWire(req) +func (c *internalClient) UpdateMaterializedFeature(ctx context.Context, req UpdateMaterializedFeatureRequest, opts ...call.Option) (*MaterializedFeature, error) { + wireReq, err := updateMaterializedFeatureRequestToWire(&req) if err != nil { return nil, err } @@ -1482,7 +1816,11 @@ func (c *internalClient) UpdateMaterializedFeature(ctx context.Context, req *Upd } pb := pathBuilder{} pb.literal("/api/2.0/feature-engineering/materialized-features/") - pb.singleSegment(*req.MaterializedFeature.MaterializedFeatureId) + if req.MaterializedFeature == nil || req.MaterializedFeature.MaterializedFeatureId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MaterializedFeature.MaterializedFeatureId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -1532,8 +1870,8 @@ func (c *internalClient) UpdateMaterializedFeature(ctx context.Context, req *Upd } // Update a Stream. Only fields listed in `update_mask` are mutated. -func (c *internalClient) UpdateStream(ctx context.Context, req *UpdateStreamRequest, opts ...call.Option) (*Stream, error) { - wireReq, err := updateStreamRequestToWire(req) +func (c *internalClient) UpdateStream(ctx context.Context, req UpdateStreamRequest, opts ...call.Option) (*Stream, error) { + wireReq, err := updateStreamRequestToWire(&req) if err != nil { return nil, err } @@ -1554,7 +1892,11 @@ func (c *internalClient) UpdateStream(ctx context.Context, req *UpdateStreamRequ } pb := pathBuilder{} pb.literal("/api/2.0/feature-engineering/streams/") - pb.singleSegment(*req.Stream.Name) + if req.Stream == nil || req.Stream.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Stream.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { diff --git a/features/v1/genhelper.go b/features/v1/genhelper.go old mode 100755 new mode 100644 index e6b43e0..a25db80 --- a/features/v1/genhelper.go +++ b/features/v1/genhelper.go @@ -5,7 +5,9 @@ package features import ( "bytes" "context" + "crypto/rand" "encoding/json" + "errors" "fmt" "io" "log/slog" @@ -18,6 +20,7 @@ import ( "github.com/databricks/sdk-go/core/ops" "github.com/databricks/sdk-go/options/call" "github.com/databricks/sdk-go/options/internaloptions" + "github.com/databricks/sdk-go/options/lro" ) type httpCallOptions struct { @@ -146,6 +149,32 @@ func executeCall(ctx context.Context, op func(context.Context) error, opts []cal return ops.Execute(ctx, op, opsOpts...) } +func validateOperationName(operationName *string) error { + if operationName == nil || *operationName == "" { + return errors.New("invalid operation response: missing operation name") + } + return nil +} + +var errOperationStillRunning = errors.New("operation is still running") + +func executeWait(ctx context.Context, operation func(context.Context) error, opts ...lro.Option) error { + cfg := internaloptions.LROOptions{} + for _, opt := range opts { + if err := opt(&cfg); err != nil { + return err + } + } + return ops.Execute(ctx, operation, + ops.WithTimeout(cfg.Timeout), + ops.WithRetrier(func() ops.Retrier { + return ops.RetryIf(ops.BackoffPolicy{}, func(err error) bool { + return errors.Is(err, errOperationStillRunning) + }) + }), + ) +} + func addQueryValue(params url.Values, key string, value any) error { data, err := json.Marshal(value) if err != nil { @@ -178,11 +207,25 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// generateRequestID returns a random RFC 4122 version 4 UUID string, used as an +// idempotency token when the caller does not supply one. It uses crypto/rand to +// avoid a UUID dependency; a read failure is treated as unrecoverable. +func generateRequestID() string { + var b [16]byte + if _, err := rand.Read(b[:]); err != nil { + panic(fmt.Sprintf("generate request id: %v", err)) + } + b[6] = (b[6] & 0x0f) | 0x40 // version 4 + b[8] = (b[8] & 0x3f) | 0x80 // variant 10 + return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:16]) +} + +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +238,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/features/v1/model.go b/features/v1/model.go old mode 100755 new mode 100644 index b0bec27..daf0ea1 --- a/features/v1/model.go +++ b/features/v1/model.go @@ -3,9 +3,408 @@ package features import ( + "encoding/json" + "fmt" + "github.com/databricks/sdk-go/core/types" ) +// Error codes returned by Databricks APIs to indicate specific failure +// conditions. +type ErrorCode string + +const ( + ErrorCode_Unspecified ErrorCode = "" + // Internal error. This means that some invariants expected by the underlying + // system have been broken. This error code is reserved for serious errors, + // which generally cannot be resolved by the user. + // + // Prefer this over all kinds of detailed error messages (e.g IO_ERROR), unless + // there's some automation that relies on the custom error code. + // + // Maps to: - google.rpc.Code: INTERNAL = 13; - HTTP code: 500 Internal Server + // Error + ErrorCode_InternalError ErrorCode = "INTERNAL_ERROR" + // The service is currently unavailable. This is most likely a transient + // condition, which can be corrected by retrying with a backoff. Note that it is + // not always safe to retry non-idempotent operations. + // + // Prefer this over SERVICE_UNDER_MAINTENANCE, + // WORKSPACE_TEMPORARILY_UNAVAILABLE. + // + // See + // https://docs.google.com/document/d/1FL8p2sbYWqBPL-UvhzI7uXAw4EoLG7Rj6PAOQWZRSOk/edit# + // for guideline on how to pick this vs RESOURCE_EXHAUSTED. + // + // Maps to: - google.rpc.Code: UNAVAILABLE = 14; - HTTP code: 503 Service + // Unavailable + ErrorCode_TemporarilyUnavailable ErrorCode = "TEMPORARILY_UNAVAILABLE" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. Indicates that an IOException has been internally + // thrown. + ErrorCode_IoError ErrorCode = "IO_ERROR" + // The request is invalid. Prefer more specific error code whenever possible. + // Also see similar recommendation for the google.rpc.Code.FAILED_PRECONDITION. + // + // Prefer this error code over MALFORMED_REQUEST, INVALID_STATE, + // UNPARSEABLE_HTTP_ERROR. + // + // Maps to: - google.rpc.Code: FAILED_PRECONDITION = 9; - HTTP code: 400 Bad + // Request + ErrorCode_BadRequest ErrorCode = "BAD_REQUEST" + // An external service is unavailable temporarily as it is being + // updated/re-deployed. Indicates gateway proxy to safely retry the request. + ErrorCode_ServiceUnderMaintenance ErrorCode = "SERVICE_UNDER_MAINTENANCE" + // A workspace is temporarily unavailable as the workspace is being re-assigned. + ErrorCode_WorkspaceTemporarilyUnavailable ErrorCode = "WORKSPACE_TEMPORARILY_UNAVAILABLE" + // The deadline expired before the operation could complete. For operations that + // change the state of the system, this error may be returned even if the + // operation has completed successfully. For example, a successful response from + // a server could have been delayed long enough for the deadline to expire. When + // possible - implementations should make sure further processing of the request + // is aborted, e.g. by throwing an exception instead of making the RPC request, + // making the database query, etc. + // + // Maps to: - google.rpc.Code: DEADLINE_EXCEEDED = 4; - HTTP code: 504 Gateway + // Timeout + ErrorCode_DeadlineExceeded ErrorCode = "DEADLINE_EXCEEDED" + // The operation was canceled by the caller. An example - client closed the + // connection without waiting for a response. + // + // Maps to: - google.rpc.Code: CANCELLED = 1; - HTTP code: 499 Client Closed + // Request + ErrorCode_Cancelled ErrorCode = "CANCELLED" + // The operation is rejected because of either rate limiting or resource quota, + // such as the client has sent too many requests recently or the client has + // allocated too many resources. + // + // See + // https://docs.google.com/document/d/1FL8p2sbYWqBPL-UvhzI7uXAw4EoLG7Rj6PAOQWZRSOk/edit# + // for guideline on how to pick this vs TEMPORARILY_UNAVAILABLE. + // + // Maps to: - google.rpc.Code: RESOURCE_EXHAUSTED = 8; - HTTP code: 429 Too Many + // Requests + ErrorCode_ResourceExhausted ErrorCode = "RESOURCE_EXHAUSTED" + // The operation was aborted, typically due to a concurrency issue such as a + // sequencer check failure, transaction abort, or transaction conflict. + // + // Maps to: - google.rpc.Code: ABORTED = 10; - HTTP code: 409 Conflict + ErrorCode_Aborted ErrorCode = "ABORTED" + // Operation was performed on a resource that does not exist, e.g. file or + // directory was not found. + // + // Maps to: - google.rpc.Code: NOT_FOUND = 5; - HTTP code: 404 Not Found + ErrorCode_NotFound ErrorCode = "NOT_FOUND" + // Operation was rejected due a conflict with an existing resource, e.g. + // attempted to create file or directory that already exists. + // + // Prefer this over RESOURCE_CONFLICT. + // + // Maps to: - google.rpc.Code: ALREADY_EXISTS = 6; - HTTP code: 409 Conflict + ErrorCode_AlreadyExists ErrorCode = "ALREADY_EXISTS" + // The request does not have valid authentication (AuthN) credentials for the + // operation. + // + // Prefer this over CUSTOMER_UNAUTHORIZED, unless you need to keep consistent + // behavior with legacy code. For authorization (AuthZ) errors use + // PERMISSION_DENIED. Maps to: - google.rpc.Code: UNAUTHENTICATED = 16; - HTTP + // code: 401 Unauthorized + ErrorCode_Unauthenticated ErrorCode = "UNAUTHENTICATED" + // The service is currently unavailable. Please note that the unavailability may + // or may not be transient. That means if this is a non-transient condition, + // retrying it does not work. If the unavailability is certainly a transient + // condition, pleases use `TEMPORARILY_UNAVAILABLE` which signals its transient + // nature explicitly. An example of this error code’s use case is that when + // DNS resolution fails, the DNS resolver does not know whether it is because + // the domain name is completely wrong (non-transient situation) or the domain + // name is valid but the DNS server does not have an entry for this domain name + // yet (transient situation). Hence, `UNAVAILABLE` is suitable for this case. + // + // Maps to: - google.rpc.Code: UNAVAILABLE = 14; - HTTP code: 503 Service + // Unavailable + ErrorCode_Unavailable ErrorCode = "UNAVAILABLE" + // Supplied value for a parameter was invalid (e.g., giving a number for a + // string parameter). + // + // Maps to: - google.rpc.Code: INVALID_ARGUMENT = 3; - HTTP code: 400 Bad + // Request + ErrorCode_InvalidParameterValue ErrorCode = "INVALID_PARAMETER_VALUE" + // Indicates that the given API endpoint does not exist. Legacy, when possible - + // NOT_IMPLEMENTED should be used instead to indicate that API doesn't exist. + // + // Maps to: - google.rpc.Code: NOT_FOUND = 5; - HTTP code: 404 Not Found + ErrorCode_EndpointNotFound ErrorCode = "ENDPOINT_NOT_FOUND" + // Indicates that the given API request was malformed. + ErrorCode_MalformedRequest ErrorCode = "MALFORMED_REQUEST" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. If one or more of the inputs to a given RPC are not in + // a valid state for the action. + ErrorCode_InvalidState ErrorCode = "INVALID_STATE" + // The caller does not have permission to execute the specified operation. + // PERMISSION_DENIED must not be used for rejections caused by exhausting some + // resource, use RESOURCE_EXHAUSTED instead for those errors. PERMISSION_DENIED + // must not be used if the caller can not be identified, use + // CUSTOMER_UNAUTHORIZED instead for those errors. This error code does not + // imply the request is valid or the requested entity exists or satisfies other + // pre-conditions. + // + // Maps to: - google.rpc.Code: PERMISSION_DENIED = 7; - HTTP code: 403 Forbidden + ErrorCode_PermissionDenied ErrorCode = "PERMISSION_DENIED" + // NOTE: Deprecated due to inconsistent mapping in legacy code, see + // https://docs.google.com/document/d/17TZIKX_Y39cJMBr333lc-d5dTvvBLSu3DPUyGU5eMJg/edit?disco=AAAAzVGt6FA. + // Prefer using NOT_FOUND or PERMISSION_DENIED. + // + // If a given user/entity is trying to use a feature which has been disabled. + // + // Maps to: - google.rpc.Code: NOT_FOUND = 5; - HTTP code: 404 Not Found + ErrorCode_FeatureDisabled ErrorCode = "FEATURE_DISABLED" + // The request does not have valid authentication (AuthN) credentials for the + // operation. + // + // For authentication (AuthN) errors prefer using UNAUTHENTICATED, unless you + // need to keep consistent behavior with legacy code. For authorization (AuthZ) + // errors use PERMISSION_DENIED. + // + // Important: name is confusing, this error code is for authentication (AuthN) + // errors, not authorization (AuthZ) errors. It maps to 401 Unauthorized and + // suffers from the same confusing naming. See + // https://datatracker.ietf.org/doc/html/rfc7235#section-3.1 - "[...] status + // code indicates that the request has not been applied because it lacks valid + // authentication credentials for the target resource. [...] If the request + // included authentication credentials, then the 401 response indicates that + // authorization has been refused for those credentials." + // + // Also, see https://stackoverflow.com/a/6937030/16352922, it covers it pretty + // well. + // + // Maps to: - google.rpc.Code: UNAUTHENTICATED = 16; - HTTP code: 401 + // Unauthorized + ErrorCode_CustomerUnauthorized ErrorCode = "CUSTOMER_UNAUTHORIZED" + // The operation is rejected because of request rate limit, for example rate + // limiting applied to users, workspaces, IP addresses, etc. + // + // Prefer a more generic RESOURCE_EXHAUSTED for the new use cases. + // + // See + // https://docs.google.com/document/d/1FL8p2sbYWqBPL-UvhzI7uXAw4EoLG7Rj6PAOQWZRSOk/edit# + // for guideline on the rate limiting vs throttling. + // + // Maps to: - google.rpc.Code: RESOURCE_EXHAUSTED = 8; - HTTP code: 429 Too Many + // Requests + ErrorCode_RequestLimitExceeded ErrorCode = "REQUEST_LIMIT_EXCEEDED" + // Indicates API request was rejected due a conflict with an existing resource. + ErrorCode_ResourceConflict ErrorCode = "RESOURCE_CONFLICT" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. Indicates that the HTTP response cannot be correctly + // deserialized. This currently is only used in DUST test clients, and not by + // any real service code. + ErrorCode_UnparseableHttpError ErrorCode = "UNPARSEABLE_HTTP_ERROR" + // The operation is not implemented or is not supported/enabled in this service. + // + // Maps to: - google.rpc.Code: UNIMPLEMENTED = 12; - HTTP code: 501 Not + // Implemented + ErrorCode_NotImplemented ErrorCode = "NOT_IMPLEMENTED" + // Unrecoverable data loss or corruption. + // + // One of the major use cases is to indicate that server failed to validate the + // integrity of the request. This error can occur when the checksum specified in + // the `X-Databricks-Checksum` request header (or trailer) doesn't match the + // actual request content checksum. + // + // Note, in case of the severe corruption that results in a malformed request, + // the server may send a generic `400 Bad Request` response rather than sending + // this error code. + // + // Maps to: - google.rpc.Code: DATA_LOSS = 15; - HTTP code: 500 Internal Server + // Error + ErrorCode_DataLoss ErrorCode = "DATA_LOSS" + // If the user attempts to perform an invalid state transition on a shard. + ErrorCode_InvalidStateTransition ErrorCode = "INVALID_STATE_TRANSITION" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. Unable to perform the operation because the shard was + // locked by some other operation. + ErrorCode_CouldNotAcquireLock ErrorCode = "COULD_NOT_ACQUIRE_LOCK" + // NOTE: Deprecated, prefer using ALREADY_EXISTS. Unlike ALREADY_EXISTS - this + // maps to HTTP code 400 Bad Request due to legacy reasons, remapping will be a + // backwards incompatible change. + // + // Operation was performed on a resource that already exists. + ErrorCode_ResourceAlreadyExists ErrorCode = "RESOURCE_ALREADY_EXISTS" + // NOTE: Deprecated, prefer using NOT_FOUND - see the note for the + // RESOURCE_ALREADY_EXISTS, because this pair of codes is related and + // RESOURCE_ALREADY_EXISTS has bad mapping to the HTTP codes we added new error + // codes NOT_FOUND and ALREADY_EXISTS, and recommend to use them instead. + // + // Operation was performed on a resource that does not exist. + ErrorCode_ResourceDoesNotExist ErrorCode = "RESOURCE_DOES_NOT_EXIST" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_QuotaExceeded ErrorCode = "QUOTA_EXCEEDED" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_MaxBlockSizeExceeded ErrorCode = "MAX_BLOCK_SIZE_EXCEEDED" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_MaxReadSizeExceeded ErrorCode = "MAX_READ_SIZE_EXCEEDED" + ErrorCode_PartialDelete ErrorCode = "PARTIAL_DELETE" + ErrorCode_MaxListSizeExceeded ErrorCode = "MAX_LIST_SIZE_EXCEEDED" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_DryRunFailed ErrorCode = "DRY_RUN_FAILED" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. Cluster request was rejected because it would exceed a + // resource limit. + ErrorCode_ResourceLimitExceeded ErrorCode = "RESOURCE_LIMIT_EXCEEDED" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_DirectoryNotEmpty ErrorCode = "DIRECTORY_NOT_EMPTY" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_DirectoryProtected ErrorCode = "DIRECTORY_PROTECTED" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_MaxNotebookSizeExceeded ErrorCode = "MAX_NOTEBOOK_SIZE_EXCEEDED" + ErrorCode_MaxChildNodeSizeExceeded ErrorCode = "MAX_CHILD_NODE_SIZE_EXCEEDED" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_SearchQueryTooLong ErrorCode = "SEARCH_QUERY_TOO_LONG" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_SearchQueryTooShort ErrorCode = "SEARCH_QUERY_TOO_SHORT" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_ManagedResourceGroupDoesNotExist ErrorCode = "MANAGED_RESOURCE_GROUP_DOES_NOT_EXIST" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_PermissionNotPropagated ErrorCode = "PERMISSION_NOT_PROPAGATED" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_DeploymentTimeout ErrorCode = "DEPLOYMENT_TIMEOUT" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_GitConflict ErrorCode = "GIT_CONFLICT" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_GitUnknownRef ErrorCode = "GIT_UNKNOWN_REF" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_GitSensitiveTokenDetected ErrorCode = "GIT_SENSITIVE_TOKEN_DETECTED" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_GitUrlNotOnAllowList ErrorCode = "GIT_URL_NOT_ON_ALLOW_LIST" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_GitRemoteError ErrorCode = "GIT_REMOTE_ERROR" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_ProjectsOperationTimeout ErrorCode = "PROJECTS_OPERATION_TIMEOUT" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_IpynbFileInRepo ErrorCode = "IPYNB_FILE_IN_REPO" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_InsecurePartnerResponse ErrorCode = "INSECURE_PARTNER_RESPONSE" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_MalformedPartnerResponse ErrorCode = "MALFORMED_PARTNER_RESPONSE" + ErrorCode_MetastoreDoesNotExist ErrorCode = "METASTORE_DOES_NOT_EXIST" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_DacDoesNotExist ErrorCode = "DAC_DOES_NOT_EXIST" + ErrorCode_CatalogDoesNotExist ErrorCode = "CATALOG_DOES_NOT_EXIST" + ErrorCode_SchemaDoesNotExist ErrorCode = "SCHEMA_DOES_NOT_EXIST" + ErrorCode_TableDoesNotExist ErrorCode = "TABLE_DOES_NOT_EXIST" + ErrorCode_ShareDoesNotExist ErrorCode = "SHARE_DOES_NOT_EXIST" + ErrorCode_RecipientDoesNotExist ErrorCode = "RECIPIENT_DOES_NOT_EXIST" + ErrorCode_StorageCredentialDoesNotExist ErrorCode = "STORAGE_CREDENTIAL_DOES_NOT_EXIST" + ErrorCode_ExternalLocationDoesNotExist ErrorCode = "EXTERNAL_LOCATION_DOES_NOT_EXIST" + ErrorCode_PrincipalDoesNotExist ErrorCode = "PRINCIPAL_DOES_NOT_EXIST" + ErrorCode_ProviderDoesNotExist ErrorCode = "PROVIDER_DOES_NOT_EXIST" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_MetastoreAlreadyExists ErrorCode = "METASTORE_ALREADY_EXISTS" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_DacAlreadyExists ErrorCode = "DAC_ALREADY_EXISTS" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_CatalogAlreadyExists ErrorCode = "CATALOG_ALREADY_EXISTS" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_SchemaAlreadyExists ErrorCode = "SCHEMA_ALREADY_EXISTS" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_TableAlreadyExists ErrorCode = "TABLE_ALREADY_EXISTS" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_ShareAlreadyExists ErrorCode = "SHARE_ALREADY_EXISTS" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_RecipientAlreadyExists ErrorCode = "RECIPIENT_ALREADY_EXISTS" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_StorageCredentialAlreadyExists ErrorCode = "STORAGE_CREDENTIAL_ALREADY_EXISTS" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_ExternalLocationAlreadyExists ErrorCode = "EXTERNAL_LOCATION_ALREADY_EXISTS" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_ProviderAlreadyExists ErrorCode = "PROVIDER_ALREADY_EXISTS" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_CatalogNotEmpty ErrorCode = "CATALOG_NOT_EMPTY" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_SchemaNotEmpty ErrorCode = "SCHEMA_NOT_EMPTY" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_MetastoreNotEmpty ErrorCode = "METASTORE_NOT_EMPTY" + // NOTE: Deprecated and kept to maintain backwards compatibility for public APIs + // that use it, avoid using it in the new APIs, refer error codes listed in the + // http://go/error-codes. + ErrorCode_ProviderShareNotAccessible ErrorCode = "PROVIDER_SHARE_NOT_ACCESSIBLE" +) + // Scalar data types for request-time field definitions. Only flat (non-nested) // types are supported. type ScalarDataType string @@ -25,6 +424,23 @@ const ( ScalarDataType_Decimal ScalarDataType = "DECIMAL" ) +// Lifecycle state of a backfill. +type BackfillOperationMetadata_State string + +const ( + BackfillOperationMetadata_State_Unspecified BackfillOperationMetadata_State = "" + // The backfill is pending. + BackfillOperationMetadata_State_Pending BackfillOperationMetadata_State = "PENDING" + // The backfill is running. + BackfillOperationMetadata_State_Running BackfillOperationMetadata_State = "RUNNING" + // The backfill succeeded. + BackfillOperationMetadata_State_Succeeded BackfillOperationMetadata_State = "SUCCEEDED" + // The backfill failed. + BackfillOperationMetadata_State_Failed BackfillOperationMetadata_State = "FAILED" + // The backfill was cancelled. + BackfillOperationMetadata_State_Cancelled BackfillOperationMetadata_State = "CANCELLED" +) + type MaterializedFeature_PipelineScheduleState string const ( @@ -215,6 +631,14 @@ type aggregationFunctionOperationFieldMaskMetadata struct { *AggregationFunction_Operation_LastDistinct } +// Databricks Error that is returned by all Databricks APIs.. +type ApiError struct { + ErrorCode ErrorCode + Message *string + StackTrace *string + Details []json.RawMessage +} + // Computes the approximate count of distinct values.. type ApproxCountDistinctFunction struct { // The input column from which the approximate count of distinct values is @@ -275,6 +699,38 @@ type AvgFunction struct { Input *string `fieldmask:"input"` } +type BackfillFeaturesRequest struct { + // Full names of the features to backfill. + FeatureFullNames []string + // Output ranges to backfill. + BackfillRanges []BackfillRange + // Idempotency token for the request. + RequestId *string +} + +// Result of a completed backfill.. +type BackfillFeaturesResponse struct { +} + +// Progress and configuration for a backfill.. +type BackfillOperationMetadata struct { + // Full names of the features targeted by the backfill. + FeatureFullNames []string + // Output ranges targeted by the backfill. + BackfillRanges []BackfillRange + // Current state of the backfill. + State BackfillOperationMetadata_State +} + +// A time range for a backfill.. +type BackfillRange struct { + // Start of the backfill range, inclusive. If unset, defaults to the earliest + // source timestamp of the feature. + StartTime *types.Time + // End of the backfill range, exclusive. If unset, defaults to the current time. + EndTime *types.Time +} + type BackfillSource struct { BackfillSource isBackfillSource_BackfillSource _ [0]backfillSourceBackfillSourceFieldMaskMetadata `fieldmask_oneof:"BackfillSource"` @@ -318,6 +774,12 @@ type BatchCreateMaterializedFeaturesResponse struct { MaterializedFeatures []MaterializedFeature } +// The request message for `CancelOperation` method.. +type CancelOperationRequest struct { + // The name of the operation resource to be cancelled. + Name *string +} + // A ColumnSelection function, equivalent to the LAST() record of an entity over // a lifetime window. type ColumnSelection struct { @@ -633,6 +1095,12 @@ type GetMaterializedFeatureRequest struct { MaterializedFeatureId *string } +// The request message for `GetOperation` method.. +type GetOperationRequest struct { + // The name of the operation resource. + Name *string +} + // Get a Stream by its full three-part name (catalog.schema.stream).. type GetStreamRequest struct { // Full three-part name (catalog.schema.stream) of the Stream to get. @@ -652,7 +1120,8 @@ type IngestionConfig struct { // creating a training set from streaming features linked to this Stream. The // backfill data stored in this location will be copied into the ingestion table // for offline querying and training. The schema for this source must match - // exactly that of the key and payload schemas specified for this Stream. + // exactly that of the key and payload schemas specified for this Stream, except + // that it may omit any columns listed in excluded_columns. BackfillSource *BackfillSource `fieldmask:"backfill_source"` // Column paths used to identify duplicate rows during ingestion; only one row // per distinct combination of these values is kept. Use dot notation for nested @@ -820,8 +1289,13 @@ type KinesisStreamConfig struct { // both). A single Stream may read from one or more Kinesis streams. StreamIdentifier isKinesisStreamConfig_StreamIdentifier // Optional Kinesis source options, validated against a server-side allowlist at - // request time. Auth and connection details belong on the parent Stream's - // `connection_config`, not here. + // request time. Allowed keys: - `consumerMode` - `consumerNamePrefix` - + // `maxFetchRate` - `minFetchPeriod` - `maxFetchDuration` - `maxRecordsPerFetch` + // - `shardsPerTask` - `fetchBufferSize` - `shardFetchInterval` `consumerMode` + // must be `efo` or `polling` (case-insensitive). `maxRecordsPerFetch` applies + // only during ingestion and does not affect the materialization pipeline. Auth + // and connection details belong on the parent Stream's `connection_config`, not + // here. ExtraOptions map[string]string `fieldmask:"extra_options"` _ [0]kinesisStreamConfigStreamIdentifierFieldMaskMetadata `fieldmask_oneof:"StreamIdentifier"` } @@ -1139,6 +1613,48 @@ type OnlineStoreConfig struct { OnlineStoreName *string `fieldmask:"online_store_name"` } +// This resource represents a long-running operation that is the result of a +// network API call.. +type Operation struct { + // The server-assigned name, which is only unique within the same service that + // originally returns it. If you use the default HTTP mapping, the `name` should + // be a resource name ending with `operations/{unique_id}`. + Name *string + // Service-specific metadata associated with the operation. It typically + // contains progress information and common metadata such as create time. Some + // services might not provide such metadata. + Metadata json.RawMessage + // If the value is `false`, it means the operation is still in progress. If + // `true`, the operation is completed, and either `error` or `response` is + // available. + Done *bool + // The operation result, which can be either an `error` or a valid `response`. + // If `done` == `false`, neither `error` nor `response` is set. If `done` == + // `true`, exactly one of `error` or `response` can be set. Some services might + // not provide the result. + Result isOperation_Result +} + +type isOperation_Result interface { + isOperation_Result() +} + +// Operation_Result_Error selects Error for Operation.Result. +// The error result of the operation in case of failure or cancellation. +type Operation_Result_Error struct { + Error ApiError +} + +func (*Operation_Result_Error) isOperation_Result() {} + +// Operation_Result_Response selects Response for Operation.Result. +// The normal, successful response of the operation. +type Operation_Result_Response struct { + Response json.RawMessage +} + +func (*Operation_Result_Response) isOperation_Result() {} + // A Protocol Buffer schema paired with the name of the message within it that // describes the Kafka payload. A .proto file may declare multiple messages; // message_name disambiguates.. @@ -1379,6 +1895,20 @@ type Stream struct { // Configuration for streaming data ingestion: the managed table storing an // offline copy of forward fill data and optional historical backfill. IngestionConfig *IngestionConfig `fieldmask:"ingestion_config"` + // Optional SQL predicate to filter which record types from a streaming channel + // (e.g. a topic for Kafka) belong to this Stream. Events that do not match are + // not written to the ingestion table and are not used in materialization. + // Example: "value.event_type = 'transaction'". + RecordTypeFilter *string `fieldmask:"record_type_filter"` + // Column paths (dot notation, e.g. "value.email" for Kafka) to drop. A path may + // reference a struct, in which case all of its nested fields are dropped (e.g. + // "value.address" drops "value.address.city" and "value.address.zip"). These + // columns are not written to the ingestion table and cannot be referenced by + // any feature. They are dropped from ingestion, backfill, and materialization. + // For direct schemas, each column must exist in the relevant key or payload + // schema. With a schema registry, a column can be excluded before it exists. A + // column cannot also be a deduplication column in the ingestion_config. + ExcludedColumns []string `fieldmask:"excluded_columns"` // Time at which this Stream was created. CreateTime *types.Time `fieldmask:"create_time"` // Username of the Stream creator. @@ -1712,3 +2242,15 @@ type VarSampFunction struct { // The input column from which the sample variance is computed. Input *string `fieldmask:"input"` } + +// Error returns the LRO error code and message. +func (e *ApiError) Error() string { + message := "unknown error" + if e.Message != nil && *e.Message != "" { + message = *e.Message + } + if e.ErrorCode != "" { + return fmt.Sprintf("[%v] %s", e.ErrorCode, message) + } + return message +} diff --git a/features/v1/wire.go b/features/v1/wire.go old mode 100755 new mode 100644 index fb1096d..9bc3b8d --- a/features/v1/wire.go +++ b/features/v1/wire.go @@ -3,11 +3,57 @@ package features import ( + "bytes" + "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + func fieldMaskToWire[T any](mask *types.FieldMask[T]) *string { if mask == nil { return nil @@ -399,6 +445,25 @@ func aggregationFunctionFromWire(w *aggregationFunctionWire) (*AggregationFuncti }, nil } +type apiErrorWire struct { + ErrorCode ErrorCode `json:"error_code,omitempty"` + Message *string `json:"message,omitempty"` + StackTrace *string `json:"stack_trace,omitempty"` + Details []json.RawMessage `json:"details,omitempty"` +} + +func apiErrorFromWire(w *apiErrorWire) (*ApiError, error) { + if w == nil { + return nil, nil + } + return &ApiError{ + ErrorCode: w.ErrorCode, + Message: w.Message, + StackTrace: w.StackTrace, + Details: w.Details, + }, nil +} + type approxCountDistinctFunctionWire struct { Input *string `json:"input,omitempty"` RelativeSd *float64 `json:"relative_sd,omitempty"` @@ -425,19 +490,23 @@ func approxCountDistinctFunctionFromWire(w *approxCountDistinctFunctionWire) (*A } type approxPercentileFunctionWire struct { - Input *string `json:"input,omitempty"` - Percentile *float64 `json:"percentile,omitempty"` - Accuracy *int64 `json:"accuracy,omitempty"` + Input *string `json:"input,omitempty"` + Percentile *float64 `json:"percentile,omitempty"` + Accuracy *wireInt64 `json:"accuracy,omitempty"` } func approxPercentileFunctionToWire(v *ApproxPercentileFunction) (*approxPercentileFunctionWire, error) { if v == nil { return nil, nil } + accuracyWireValue, err := int64ToWire(v.Accuracy) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ApproxPercentileFunction.Accuracy", err) + } return &approxPercentileFunctionWire{ Input: v.Input, Percentile: v.Percentile, - Accuracy: v.Accuracy, + Accuracy: accuracyWireValue, }, nil } @@ -445,10 +514,14 @@ func approxPercentileFunctionFromWire(w *approxPercentileFunctionWire) (*ApproxP if w == nil { return nil, nil } + accuracyPublicValue, err := int64FromWire(w.Accuracy) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ApproxPercentileFunction.Accuracy", err) + } return &ApproxPercentileFunction{ Input: w.Input, Percentile: w.Percentile, - Accuracy: w.Accuracy, + Accuracy: accuracyPublicValue, }, nil } @@ -538,6 +611,83 @@ func avgFunctionFromWire(w *avgFunctionWire) (*AvgFunction, error) { }, nil } +type backfillFeaturesRequestWire struct { + FeatureFullNames []string `json:"feature_full_names,omitempty"` + BackfillRanges []backfillRangeWire `json:"backfill_ranges,omitempty"` + RequestId *string `json:"request_id,omitempty"` +} + +func backfillFeaturesRequestToWire(v *BackfillFeaturesRequest) (*backfillFeaturesRequestWire, error) { + if v == nil { + return nil, nil + } + backfillRangesWireValue, err := convertSlice(v.BackfillRanges, backfillRangeToWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BackfillFeaturesRequest.BackfillRanges", err) + } + return &backfillFeaturesRequestWire{ + FeatureFullNames: v.FeatureFullNames, + BackfillRanges: backfillRangesWireValue, + RequestId: v.RequestId, + }, nil +} + +type backfillFeaturesResponseWire struct { +} + +func backfillFeaturesResponseFromWire(w *backfillFeaturesResponseWire) (*BackfillFeaturesResponse, error) { + if w == nil { + return nil, nil + } + return &BackfillFeaturesResponse{}, nil +} + +type backfillOperationMetadataWire struct { + FeatureFullNames []string `json:"feature_full_names,omitempty"` + BackfillRanges []backfillRangeWire `json:"backfill_ranges,omitempty"` + State BackfillOperationMetadata_State `json:"state,omitempty"` +} + +func backfillOperationMetadataFromWire(w *backfillOperationMetadataWire) (*BackfillOperationMetadata, error) { + if w == nil { + return nil, nil + } + backfillRangesPublicValue, err := convertSlice(w.BackfillRanges, backfillRangeFromWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BackfillOperationMetadata.BackfillRanges", err) + } + return &BackfillOperationMetadata{ + FeatureFullNames: w.FeatureFullNames, + BackfillRanges: backfillRangesPublicValue, + State: w.State, + }, nil +} + +type backfillRangeWire struct { + StartTime *types.Time `json:"start_time,omitempty"` + EndTime *types.Time `json:"end_time,omitempty"` +} + +func backfillRangeToWire(v *BackfillRange) (*backfillRangeWire, error) { + if v == nil { + return nil, nil + } + return &backfillRangeWire{ + StartTime: v.StartTime, + EndTime: v.EndTime, + }, nil +} + +func backfillRangeFromWire(w *backfillRangeWire) (*BackfillRange, error) { + if w == nil { + return nil, nil + } + return &BackfillRange{ + StartTime: w.StartTime, + EndTime: w.EndTime, + }, nil +} + type backfillSourceWire struct { DeltaTableSource *deltaTableSourceWire `json:"delta_table_source,omitempty"` DeltaTableName *string `json:"delta_table_name,omitempty"` @@ -636,6 +786,19 @@ func batchCreateMaterializedFeaturesResponseFromWire(w *batchCreateMaterializedF }, nil } +type cancelOperationRequestWire struct { + Name *string `json:"name,omitempty"` +} + +func cancelOperationRequestToWire(v *CancelOperationRequest) (*cancelOperationRequestWire, error) { + if v == nil { + return nil, nil + } + return &cancelOperationRequestWire{ + Name: v.Name, + }, nil +} + type columnSelectionWire struct { Column *string `json:"column,omitempty"` } @@ -1174,17 +1337,21 @@ func fieldDefinitionFromWire(w *fieldDefinitionWire) (*FieldDefinition, error) { } type firstDistinctFunctionWire struct { - Input *string `json:"input,omitempty"` - N *int64 `json:"n,omitempty"` + Input *string `json:"input,omitempty"` + N *wireInt64 `json:"n,omitempty"` } func firstDistinctFunctionToWire(v *FirstDistinctFunction) (*firstDistinctFunctionWire, error) { if v == nil { return nil, nil } + nWireValue, err := int64ToWire(v.N) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FirstDistinctFunction.N", err) + } return &firstDistinctFunctionWire{ Input: v.Input, - N: v.N, + N: nWireValue, }, nil } @@ -1192,9 +1359,13 @@ func firstDistinctFunctionFromWire(w *firstDistinctFunctionWire) (*FirstDistinct if w == nil { return nil, nil } + nPublicValue, err := int64FromWire(w.N) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FirstDistinctFunction.N", err) + } return &FirstDistinctFunction{ Input: w.Input, - N: w.N, + N: nPublicValue, }, nil } @@ -1221,17 +1392,21 @@ func firstFunctionFromWire(w *firstFunctionWire) (*FirstFunction, error) { } type firstNFunctionWire struct { - Input *string `json:"input,omitempty"` - N *int64 `json:"n,omitempty"` + Input *string `json:"input,omitempty"` + N *wireInt64 `json:"n,omitempty"` } func firstNFunctionToWire(v *FirstNFunction) (*firstNFunctionWire, error) { if v == nil { return nil, nil } + nWireValue, err := int64ToWire(v.N) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FirstNFunction.N", err) + } return &firstNFunctionWire{ Input: v.Input, - N: v.N, + N: nWireValue, }, nil } @@ -1239,9 +1414,13 @@ func firstNFunctionFromWire(w *firstNFunctionWire) (*FirstNFunction, error) { if w == nil { return nil, nil } + nPublicValue, err := int64FromWire(w.N) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FirstNFunction.N", err) + } return &FirstNFunction{ Input: w.Input, - N: w.N, + N: nPublicValue, }, nil } @@ -1372,8 +1551,8 @@ type ingestionConfigWire struct { BackfillSource *backfillSourceWire `json:"backfill_source,omitempty"` DeduplicationColumns []string `json:"deduplication_columns,omitempty"` IngestionPipelineId *string `json:"ingestion_pipeline_id,omitempty"` - IngestionJobId *int64 `json:"ingestion_job_id,omitempty"` - BackfillJobId *int64 `json:"backfill_job_id,omitempty"` + IngestionJobId *wireInt64 `json:"ingestion_job_id,omitempty"` + BackfillJobId *wireInt64 `json:"backfill_job_id,omitempty"` } func ingestionConfigToWire(v *IngestionConfig) (*ingestionConfigWire, error) { @@ -1388,13 +1567,21 @@ func ingestionConfigToWire(v *IngestionConfig) (*ingestionConfigWire, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "IngestionConfig.BackfillSource", err) } + ingestionJobIdWireValue, err := int64ToWire(v.IngestionJobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "IngestionConfig.IngestionJobId", err) + } + backfillJobIdWireValue, err := int64ToWire(v.BackfillJobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "IngestionConfig.BackfillJobId", err) + } return &ingestionConfigWire{ IngestionDestination: ingestionDestinationWireValue, BackfillSource: backfillSourceWireValue, DeduplicationColumns: v.DeduplicationColumns, IngestionPipelineId: v.IngestionPipelineId, - IngestionJobId: v.IngestionJobId, - BackfillJobId: v.BackfillJobId, + IngestionJobId: ingestionJobIdWireValue, + BackfillJobId: backfillJobIdWireValue, }, nil } @@ -1410,13 +1597,21 @@ func ingestionConfigFromWire(w *ingestionConfigWire) (*IngestionConfig, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "IngestionConfig.BackfillSource", err) } + ingestionJobIdPublicValue, err := int64FromWire(w.IngestionJobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "IngestionConfig.IngestionJobId", err) + } + backfillJobIdPublicValue, err := int64FromWire(w.BackfillJobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "IngestionConfig.BackfillJobId", err) + } return &IngestionConfig{ IngestionDestination: ingestionDestinationPublicValue, BackfillSource: backfillSourcePublicValue, DeduplicationColumns: w.DeduplicationColumns, IngestionPipelineId: w.IngestionPipelineId, - IngestionJobId: w.IngestionJobId, - BackfillJobId: w.BackfillJobId, + IngestionJobId: ingestionJobIdPublicValue, + BackfillJobId: backfillJobIdPublicValue, }, nil } @@ -1490,17 +1685,25 @@ func inputBindingFromWire(w *inputBindingWire) (*InputBinding, error) { } type jobContextWire struct { - JobId *int64 `json:"job_id,omitempty"` - JobRunId *int64 `json:"job_run_id,omitempty"` + JobId *wireInt64 `json:"job_id,omitempty"` + JobRunId *wireInt64 `json:"job_run_id,omitempty"` } func jobContextToWire(v *JobContext) (*jobContextWire, error) { if v == nil { return nil, nil } + jobIdWireValue, err := int64ToWire(v.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "JobContext.JobId", err) + } + jobRunIdWireValue, err := int64ToWire(v.JobRunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "JobContext.JobRunId", err) + } return &jobContextWire{ - JobId: v.JobId, - JobRunId: v.JobRunId, + JobId: jobIdWireValue, + JobRunId: jobRunIdWireValue, }, nil } @@ -1508,9 +1711,17 @@ func jobContextFromWire(w *jobContextWire) (*JobContext, error) { if w == nil { return nil, nil } + jobIdPublicValue, err := int64FromWire(w.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "JobContext.JobId", err) + } + jobRunIdPublicValue, err := int64FromWire(w.JobRunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "JobContext.JobRunId", err) + } return &JobContext{ - JobId: w.JobId, - JobRunId: w.JobRunId, + JobId: jobIdPublicValue, + JobRunId: jobRunIdPublicValue, }, nil } @@ -1810,17 +2021,21 @@ func kinesisStreamConfigFromWire(w *kinesisStreamConfigWire) (*KinesisStreamConf } type lastDistinctFunctionWire struct { - Input *string `json:"input,omitempty"` - N *int64 `json:"n,omitempty"` + Input *string `json:"input,omitempty"` + N *wireInt64 `json:"n,omitempty"` } func lastDistinctFunctionToWire(v *LastDistinctFunction) (*lastDistinctFunctionWire, error) { if v == nil { return nil, nil } + nWireValue, err := int64ToWire(v.N) + if err != nil { + return nil, fmt.Errorf("%s: %w", "LastDistinctFunction.N", err) + } return &lastDistinctFunctionWire{ Input: v.Input, - N: v.N, + N: nWireValue, }, nil } @@ -1828,9 +2043,13 @@ func lastDistinctFunctionFromWire(w *lastDistinctFunctionWire) (*LastDistinctFun if w == nil { return nil, nil } + nPublicValue, err := int64FromWire(w.N) + if err != nil { + return nil, fmt.Errorf("%s: %w", "LastDistinctFunction.N", err) + } return &LastDistinctFunction{ Input: w.Input, - N: w.N, + N: nPublicValue, }, nil } @@ -1857,17 +2076,21 @@ func lastFunctionFromWire(w *lastFunctionWire) (*LastFunction, error) { } type lastNFunctionWire struct { - Input *string `json:"input,omitempty"` - N *int64 `json:"n,omitempty"` + Input *string `json:"input,omitempty"` + N *wireInt64 `json:"n,omitempty"` } func lastNFunctionToWire(v *LastNFunction) (*lastNFunctionWire, error) { if v == nil { return nil, nil } + nWireValue, err := int64ToWire(v.N) + if err != nil { + return nil, fmt.Errorf("%s: %w", "LastNFunction.N", err) + } return &lastNFunctionWire{ Input: v.Input, - N: v.N, + N: nWireValue, }, nil } @@ -1875,14 +2098,18 @@ func lastNFunctionFromWire(w *lastNFunctionWire) (*LastNFunction, error) { if w == nil { return nil, nil } + nPublicValue, err := int64FromWire(w.N) + if err != nil { + return nil, fmt.Errorf("%s: %w", "LastNFunction.N", err) + } return &LastNFunction{ Input: w.Input, - N: w.N, + N: nPublicValue, }, nil } type lineageContextWire struct { - NotebookId *int64 `json:"notebook_id,omitempty"` + NotebookId *wireInt64 `json:"notebook_id,omitempty"` JobContext *jobContextWire `json:"job_context,omitempty"` } @@ -1890,12 +2117,16 @@ func lineageContextToWire(v *LineageContext) (*lineageContextWire, error) { if v == nil { return nil, nil } + notebookIdWireValue, err := int64ToWire(v.NotebookId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "LineageContext.NotebookId", err) + } jobContextWireValue, err := jobContextToWire(v.JobContext) if err != nil { return nil, fmt.Errorf("%s: %w", "LineageContext.JobContext", err) } return &lineageContextWire{ - NotebookId: v.NotebookId, + NotebookId: notebookIdWireValue, JobContext: jobContextWireValue, }, nil } @@ -1904,12 +2135,16 @@ func lineageContextFromWire(w *lineageContextWire) (*LineageContext, error) { if w == nil { return nil, nil } + notebookIdPublicValue, err := int64FromWire(w.NotebookId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "LineageContext.NotebookId", err) + } jobContextPublicValue, err := jobContextFromWire(w.JobContext) if err != nil { return nil, fmt.Errorf("%s: %w", "LineageContext.JobContext", err) } return &LineageContext{ - NotebookId: w.NotebookId, + NotebookId: notebookIdPublicValue, JobContext: jobContextPublicValue, }, nil } @@ -2385,6 +2620,47 @@ func onlineStoreConfigFromWire(w *onlineStoreConfigWire) (*OnlineStoreConfig, er }, nil } +type operationWire struct { + Name *string `json:"name,omitempty"` + Metadata json.RawMessage `json:"metadata,omitempty"` + Done *bool `json:"done,omitempty"` + Error *apiErrorWire `json:"error,omitempty"` + Response json.RawMessage `json:"response,omitempty"` +} + +func operationFromWire(w *operationWire) (*Operation, error) { + if w == nil { + return nil, nil + } + resultMembers := 0 + if w.Error != nil { + resultMembers++ + } + if w.Response != nil { + resultMembers++ + } + if resultMembers > 1 { + return nil, fmt.Errorf("%s: multiple oneof members set", "Operation.Result") + } + var resultSelection isOperation_Result + switch { + case w.Error != nil: + resultErrorConverted, err := apiErrorFromWire(w.Error) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Operation.Result.Error", err) + } + resultSelection = &Operation_Result_Error{Error: *resultErrorConverted} + case w.Response != nil: + resultSelection = &Operation_Result_Response{Response: w.Response} + } + return &Operation{ + Name: w.Name, + Metadata: w.Metadata, + Done: w.Done, + Result: resultSelection, + }, nil +} + type protoSchemaSpecWire struct { SchemaText *string `json:"schema_text,omitempty"` MessageName *string `json:"message_name,omitempty"` @@ -2849,6 +3125,8 @@ type streamWire struct { ConnectionConfig *streamConnectionConfigWire `json:"connection_config,omitempty"` SchemaConfig *streamSchemaConfigWire `json:"schema_config,omitempty"` IngestionConfig *ingestionConfigWire `json:"ingestion_config,omitempty"` + RecordTypeFilter *string `json:"record_type_filter,omitempty"` + ExcludedColumns []string `json:"excluded_columns,omitempty"` CreateTime *types.Time `json:"create_time,omitempty"` CreatedBy *string `json:"created_by,omitempty"` UpdateTime *types.Time `json:"update_time,omitempty"` @@ -2883,6 +3161,8 @@ func streamToWire(v *Stream) (*streamWire, error) { ConnectionConfig: connectionConfigWireValue, SchemaConfig: schemaConfigWireValue, IngestionConfig: ingestionConfigWireValue, + RecordTypeFilter: v.RecordTypeFilter, + ExcludedColumns: v.ExcludedColumns, CreateTime: v.CreateTime, CreatedBy: v.CreatedBy, UpdateTime: v.UpdateTime, @@ -2918,6 +3198,8 @@ func streamFromWire(w *streamWire) (*Stream, error) { ConnectionConfig: connectionConfigPublicValue, SchemaConfig: schemaConfigPublicValue, IngestionConfig: ingestionConfigPublicValue, + RecordTypeFilter: w.RecordTypeFilter, + ExcludedColumns: w.ExcludedColumns, CreateTime: w.CreateTime, CreatedBy: w.CreatedBy, UpdateTime: w.UpdateTime, diff --git a/featurestore/CHANGELOG.md b/featurestore/CHANGELOG.md index 6224c04..19f237c 100644 --- a/featurestore/CHANGELOG.md +++ b/featurestore/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/featurestore/go.mod b/featurestore/go.mod index ad3ebb8..b6a5ac6 100644 --- a/featurestore/go.mod +++ b/featurestore/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/featurestore/internal/version.go b/featurestore/internal/version.go index fa9758c..207db38 100644 --- a/featurestore/internal/version.go +++ b/featurestore/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-featurestore" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/featurestore/v1/client.go b/featurestore/v1/client.go old mode 100755 new mode 100644 index c5d1730..0708768 --- a/featurestore/v1/client.go +++ b/featurestore/v1/client.go @@ -75,8 +75,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Create an Online Feature Store. -func (c *internalClient) CreateOnlineStore(ctx context.Context, req *CreateOnlineStoreRequest, opts ...call.Option) (*OnlineStore, error) { - wireReq, err := createOnlineStoreRequestToWire(req) +func (c *internalClient) CreateOnlineStore(ctx context.Context, req CreateOnlineStoreRequest, opts ...call.Option) (*OnlineStore, error) { + wireReq, err := createOnlineStoreRequestToWire(&req) if err != nil { return nil, err } @@ -141,7 +141,7 @@ func (c *internalClient) CreateOnlineStore(ctx context.Context, req *CreateOnlin } // Delete an Online Feature Store. -func (c *internalClient) DeleteOnlineStore(ctx context.Context, req *DeleteOnlineStoreRequest, opts ...call.Option) error { +func (c *internalClient) DeleteOnlineStore(ctx context.Context, req DeleteOnlineStoreRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -155,7 +155,11 @@ func (c *internalClient) DeleteOnlineStore(ctx context.Context, req *DeleteOnlin } pb := pathBuilder{} pb.literal("/api/2.0/feature-store/online-stores/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -192,7 +196,7 @@ func (c *internalClient) DeleteOnlineStore(ctx context.Context, req *DeleteOnlin } // Delete online table. -func (c *internalClient) DeleteOnlineTable(ctx context.Context, req *DeleteOnlineTableRequest, opts ...call.Option) error { +func (c *internalClient) DeleteOnlineTable(ctx context.Context, req DeleteOnlineTableRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -206,7 +210,11 @@ func (c *internalClient) DeleteOnlineTable(ctx context.Context, req *DeleteOnlin } pb := pathBuilder{} pb.literal("/api/2.0/feature-store/online-tables/") - pb.singleSegment(*req.OnlineTableName) + if req.OnlineTableName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.OnlineTableName) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -243,7 +251,7 @@ func (c *internalClient) DeleteOnlineTable(ctx context.Context, req *DeleteOnlin } // Get an Online Feature Store. -func (c *internalClient) GetOnlineStore(ctx context.Context, req *GetOnlineStoreRequest, opts ...call.Option) (*OnlineStore, error) { +func (c *internalClient) GetOnlineStore(ctx context.Context, req GetOnlineStoreRequest, opts ...call.Option) (*OnlineStore, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -257,7 +265,11 @@ func (c *internalClient) GetOnlineStore(ctx context.Context, req *GetOnlineStore } pb := pathBuilder{} pb.literal("/api/2.0/feature-store/online-stores/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -303,8 +315,8 @@ func (c *internalClient) GetOnlineStore(ctx context.Context, req *GetOnlineStore } // List Online Feature Stores. -func (c *internalClient) ListOnlineStores(ctx context.Context, req *ListOnlineStoresRequest, opts ...call.Option) (*ListOnlineStoresResponse, error) { - wireReq, err := listOnlineStoresRequestToWire(req) +func (c *internalClient) ListOnlineStores(ctx context.Context, req ListOnlineStoresRequest, opts ...call.Option) (*ListOnlineStoresResponse, error) { + wireReq, err := listOnlineStoresRequestToWire(&req) if err != nil { return nil, err } @@ -374,7 +386,7 @@ func (c *internalClient) ListOnlineStores(ctx context.Context, req *ListOnlineSt // // For example: // -// for item, err := range c.ListOnlineStoresIter(ctx, &ListOnlineStoresRequest{}) { +// for item, err := range c.ListOnlineStoresIter(ctx, ListOnlineStoresRequest{}) { // if err != nil { // return err // } @@ -386,16 +398,13 @@ func (c *internalClient) ListOnlineStores(ctx context.Context, req *ListOnlineSt // // Callers who need custom pagination logic should use // ListOnlineStores directly. -func (c *internalClient) ListOnlineStoresIter(ctx context.Context, req *ListOnlineStoresRequest, opts ...call.Option) iter.Seq2[*OnlineStore, error] { +func (c *internalClient) ListOnlineStoresIter(ctx context.Context, req ListOnlineStoresRequest, opts ...call.Option) iter.Seq2[*OnlineStore, error] { return func(yield func(*OnlineStore, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListOnlineStoresRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListOnlineStores(ctx, &pageReq, opts...) + resp, err := c.ListOnlineStores(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -414,8 +423,8 @@ func (c *internalClient) ListOnlineStoresIter(ctx context.Context, req *ListOnli } // Publish features. -func (c *internalClient) PublishTable(ctx context.Context, req *PublishTableRequest, opts ...call.Option) (*PublishTableResponse, error) { - wireReq, err := publishTableRequestToWire(req) +func (c *internalClient) PublishTable(ctx context.Context, req PublishTableRequest, opts ...call.Option) (*PublishTableResponse, error) { + wireReq, err := publishTableRequestToWire(&req) if err != nil { return nil, err } @@ -436,7 +445,11 @@ func (c *internalClient) PublishTable(ctx context.Context, req *PublishTableRequ } pb := pathBuilder{} pb.literal("/api/2.0/feature-store/tables/") - pb.singleSegment(*req.SourceTableName) + if req.SourceTableName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SourceTableName) + } pb.literal("/publish") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -484,8 +497,8 @@ func (c *internalClient) PublishTable(ctx context.Context, req *PublishTableRequ } // Update an Online Feature Store. -func (c *internalClient) UpdateOnlineStore(ctx context.Context, req *UpdateOnlineStoreRequest, opts ...call.Option) (*OnlineStore, error) { - wireReq, err := updateOnlineStoreRequestToWire(req) +func (c *internalClient) UpdateOnlineStore(ctx context.Context, req UpdateOnlineStoreRequest, opts ...call.Option) (*OnlineStore, error) { + wireReq, err := updateOnlineStoreRequestToWire(&req) if err != nil { return nil, err } @@ -506,7 +519,11 @@ func (c *internalClient) UpdateOnlineStore(ctx context.Context, req *UpdateOnlin } pb := pathBuilder{} pb.literal("/api/2.0/feature-store/online-stores/") - pb.singleSegment(*req.OnlineStore.Name) + if req.OnlineStore == nil || req.OnlineStore.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.OnlineStore.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { diff --git a/featurestore/v1/genhelper.go b/featurestore/v1/genhelper.go old mode 100755 new mode 100644 index 2cc6647..07a9bb6 --- a/featurestore/v1/genhelper.go +++ b/featurestore/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/files/CHANGELOG.md b/files/CHANGELOG.md index 6224c04..19f237c 100644 --- a/files/CHANGELOG.md +++ b/files/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/files/examples/upload/main.go b/files/examples/upload/main.go index 4ecb424..d6648a7 100644 --- a/files/examples/upload/main.go +++ b/files/examples/upload/main.go @@ -46,7 +46,7 @@ func main() { fmt.Printf("Uploaded %d bytes to %s\n", len(payload), remotePath) // Download the payload from the remote path. - resp, err := c.DownloadFile(ctx, &files.DownloadFileRequest{FilePath: new(remotePath)}) + resp, err := c.DownloadFile(ctx, files.DownloadFileRequest{FilePath: new(remotePath)}) if err != nil { log.Fatalf("DownloadFile: %v", err) } diff --git a/files/go.mod b/files/go.mod index 0768d9f..30c76e5 100644 --- a/files/go.mod +++ b/files/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/files/go.sum b/files/go.sum index 18b54be..3f1d82f 100644 --- a/files/go.sum +++ b/files/go.sum @@ -1,13 +1,32 @@ +github.com/databricks/databricks-sdk-go v0.92.0 h1:Pvm/LvEXetOYJPgQFeewhmtkKC4z79AK3PHC5tlC+VQ= +github.com/databricks/databricks-sdk-go v0.92.0/go.mod h1:hWoHnHbNLjPKiTm5K/7bcIv3J3Pkgo5x9pPzh8K3RVE= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/files/internal/version.go b/files/internal/version.go index ca94a8a..75f217d 100644 --- a/files/internal/version.go +++ b/files/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-files" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/files/v2/client.go b/files/v2/client.go old mode 100755 new mode 100644 index 403704e..67b7e8f --- a/files/v2/client.go +++ b/files/v2/client.go @@ -83,8 +83,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // // If the block of data exceeds 1 MB, this call will throw an exception with // “MAX_BLOCK_SIZE_EXCEEDED“. -func (c *internalClient) AddBlock(ctx context.Context, req *AddBlockRequest, opts ...call.Option) (*AddBlockResponse, error) { - wireReq, err := addBlockRequestToWire(req) +func (c *internalClient) AddBlock(ctx context.Context, req AddBlockRequest, opts ...call.Option) (*AddBlockResponse, error) { + wireReq, err := addBlockRequestToWire(&req) if err != nil { return nil, err } @@ -144,8 +144,8 @@ func (c *internalClient) AddBlock(ctx context.Context, req *AddBlockRequest, opt // Closes the stream specified by the input handle. If the handle does not // exist, this call throws an exception with “RESOURCE_DOES_NOT_EXIST“. -func (c *internalClient) Close(ctx context.Context, req *CloseRequest, opts ...call.Option) (*CloseResponse, error) { - wireReq, err := closeRequestToWire(req) +func (c *internalClient) Close(ctx context.Context, req CloseRequest, opts ...call.Option) (*CloseResponse, error) { + wireReq, err := closeRequestToWire(&req) if err != nil { return nil, err } @@ -213,8 +213,8 @@ func (c *internalClient) Close(ctx context.Context, req *CloseRequest, opts ...c // 1. Issue a “create“ call and get a handle. 2. Issue one or more // “add-block“ calls with the handle you have. 3. Issue a “close“ call with // the handle you have. -func (c *internalClient) Create(ctx context.Context, req *CreateRequest, opts ...call.Option) (*CreateResponse, error) { - wireReq, err := createRequestToWire(req) +func (c *internalClient) Create(ctx context.Context, req CreateRequest, opts ...call.Option) (*CreateResponse, error) { + wireReq, err := createRequestToWire(&req) if err != nil { return nil, err } @@ -296,8 +296,8 @@ func (c *internalClient) Create(ctx context.Context, req *CreateRequest, opts .. // such operations using notebooks provides better control and manageability, // such as selective deletes, and the possibility to automate periodic delete // jobs. -func (c *internalClient) Delete(ctx context.Context, req *DeleteRequest, opts ...call.Option) (*DeleteResponse, error) { - wireReq, err := deleteRequestToWire(req) +func (c *internalClient) Delete(ctx context.Context, req DeleteRequest, opts ...call.Option) (*DeleteResponse, error) { + wireReq, err := deleteRequestToWire(&req) if err != nil { return nil, err } @@ -357,8 +357,8 @@ func (c *internalClient) Delete(ctx context.Context, req *DeleteRequest, opts .. // Gets the file information for a file or directory. If the file or directory // does not exist, this call throws an exception with `RESOURCE_DOES_NOT_EXIST`. -func (c *internalClient) GetStatus(ctx context.Context, req *GetStatusRequest, opts ...call.Option) (*GetStatusResponse, error) { - wireReq, err := getStatusRequestToWire(req) +func (c *internalClient) GetStatus(ctx context.Context, req GetStatusRequest, opts ...call.Option) (*GetStatusResponse, error) { + wireReq, err := getStatusRequestToWire(&req) if err != nil { return nil, err } @@ -431,8 +431,8 @@ func (c *internalClient) GetStatus(ctx context.Context, req *GetStatusRequest, o // you perform such operations in the context of a cluster, using the [File // system utility (dbutils.fs)](/dev-tools/databricks-utils.html#dbutils-fs), // which provides the same functionality without timing out. -func (c *internalClient) List(ctx context.Context, req *ListStatusRequest, opts ...call.Option) (*ListStatusResponse, error) { - wireReq, err := listStatusRequestToWire(req) +func (c *internalClient) List(ctx context.Context, req ListStatusRequest, opts ...call.Option) (*ListStatusResponse, error) { + wireReq, err := listStatusRequestToWire(&req) if err != nil { return nil, err } @@ -499,8 +499,8 @@ func (c *internalClient) List(ctx context.Context, req *ListStatusRequest, opts // this call throws an exception with `RESOURCE_ALREADY_EXISTS`. **Note**: If // this operation fails, it might have succeeded in creating some of the // necessary parent directories. -func (c *internalClient) Mkdirs(ctx context.Context, req *MkDirsRequest, opts ...call.Option) (*MkDirsResponse, error) { - wireReq, err := mkDirsRequestToWire(req) +func (c *internalClient) Mkdirs(ctx context.Context, req MkDirsRequest, opts ...call.Option) (*MkDirsResponse, error) { + wireReq, err := mkDirsRequestToWire(&req) if err != nil { return nil, err } @@ -563,8 +563,8 @@ func (c *internalClient) Mkdirs(ctx context.Context, req *MkDirsRequest, opts .. // `RESOURCE_DOES_NOT_EXIST`. If a file already exists in the destination path, // this call throws an exception with `RESOURCE_ALREADY_EXISTS`. If the given // source path is a directory, this call always recursively moves all files. -func (c *internalClient) Move(ctx context.Context, req *MoveRequest, opts ...call.Option) (*MoveResponse, error) { - wireReq, err := moveRequestToWire(req) +func (c *internalClient) Move(ctx context.Context, req MoveRequest, opts ...call.Option) (*MoveResponse, error) { + wireReq, err := moveRequestToWire(&req) if err != nil { return nil, err } @@ -634,8 +634,8 @@ func (c *internalClient) Move(ctx context.Context, req *MoveRequest, opts ...cal // // If you want to upload large files, use the streaming upload. For details, see // :method:dbfs/create, :method:dbfs/addBlock, :method:dbfs/close. -func (c *internalClient) Put(ctx context.Context, req *PutRequest, opts ...call.Option) (*PutResponse, error) { - wireReq, err := putRequestToWire(req) +func (c *internalClient) Put(ctx context.Context, req PutRequest, opts ...call.Option) (*PutResponse, error) { + wireReq, err := putRequestToWire(&req) if err != nil { return nil, err } @@ -701,8 +701,8 @@ func (c *internalClient) Put(ctx context.Context, req *PutRequest, opts ...call. // // If `offset + length` exceeds the number of bytes in a file, it reads the // contents until the end of file. -func (c *internalClient) Read(ctx context.Context, req *ReadRequest, opts ...call.Option) (*ReadResponse, error) { - wireReq, err := readRequestToWire(req) +func (c *internalClient) Read(ctx context.Context, req ReadRequest, opts ...call.Option) (*ReadResponse, error) { + wireReq, err := readRequestToWire(&req) if err != nil { return nil, err } @@ -774,7 +774,7 @@ func (c *internalClient) Read(ctx context.Context, req *ReadRequest, opts ...cal // of the new, empty directory (like the shell command `mkdir -p`). If called on // an existing directory, returns a success response; this method is idempotent // (it will succeed if the directory already exists). -func (c *internalClient) CreateDirectory(ctx context.Context, req *CreateDirectoryRequest, opts ...call.Option) (*CreateDirectoryResponse, error) { +func (c *internalClient) CreateDirectory(ctx context.Context, req CreateDirectoryRequest, opts ...call.Option) (*CreateDirectoryResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -788,7 +788,11 @@ func (c *internalClient) CreateDirectory(ctx context.Context, req *CreateDirecto } pb := pathBuilder{} pb.literal("/api/2.0/fs/directories") - pb.multiSegments(*req.DirectoryPath) + if req.DirectoryPath == nil { + pb.multiSegments("") + } else { + pb.multiSegments(*req.DirectoryPath) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -832,7 +836,7 @@ func (c *internalClient) CreateDirectory(ctx context.Context, req *CreateDirecto // To delete a non-empty directory, first delete all of its contents. This can // be done by listing the directory contents and deleting each file and // subdirectory recursively. -func (c *internalClient) DeleteDirectory(ctx context.Context, req *DeleteDirectoryRequest, opts ...call.Option) (*DeleteDirectoryResponse, error) { +func (c *internalClient) DeleteDirectory(ctx context.Context, req DeleteDirectoryRequest, opts ...call.Option) (*DeleteDirectoryResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -846,7 +850,11 @@ func (c *internalClient) DeleteDirectory(ctx context.Context, req *DeleteDirecto } pb := pathBuilder{} pb.literal("/api/2.0/fs/directories") - pb.multiSegments(*req.DirectoryPath) + if req.DirectoryPath == nil { + pb.multiSegments("") + } else { + pb.multiSegments(*req.DirectoryPath) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -886,7 +894,7 @@ func (c *internalClient) DeleteDirectory(ctx context.Context, req *DeleteDirecto } // Deletes a file. If the request is successful, there is no response body. -func (c *internalClient) DeleteFile(ctx context.Context, req *DeleteFileRequest, opts ...call.Option) (*DeleteFileResponse, error) { +func (c *internalClient) DeleteFile(ctx context.Context, req DeleteFileRequest, opts ...call.Option) (*DeleteFileResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -900,7 +908,11 @@ func (c *internalClient) DeleteFile(ctx context.Context, req *DeleteFileRequest, } pb := pathBuilder{} pb.literal("/api/2.0/fs/files") - pb.multiSegments(*req.FilePath) + if req.FilePath == nil { + pb.multiSegments("") + } else { + pb.multiSegments(*req.FilePath) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -942,7 +954,7 @@ func (c *internalClient) DeleteFile(ctx context.Context, req *DeleteFileRequest, // Downloads a file. The file contents are the response body. This is a standard // HTTP file download, not a JSON RPC. It supports the Range and // If-Unmodified-Since HTTP headers. -func (c *internalClient) DownloadFile(ctx context.Context, req *DownloadFileRequest, opts ...call.Option) (*DownloadFileResponse, error) { +func (c *internalClient) DownloadFile(ctx context.Context, req DownloadFileRequest, opts ...call.Option) (*DownloadFileResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -963,7 +975,11 @@ func (c *internalClient) DownloadFile(ctx context.Context, req *DownloadFileRequ } pb := pathBuilder{} pb.literal("/api/2.0/fs/files") - pb.multiSegments(*req.FilePath) + if req.FilePath == nil { + pb.multiSegments("") + } else { + pb.multiSegments(*req.FilePath) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1027,7 +1043,7 @@ func (c *internalClient) DownloadFile(ctx context.Context, req *DownloadFileRequ // If you wish to ensure the directory exists, you can instead use `PUT`, which // will create the directory if it does not exist, and is idempotent (it will // succeed if the directory already exists). -func (c *internalClient) GetDirectoryMetadata(ctx context.Context, req *GetDirectoryMetadataRequest, opts ...call.Option) (*GetDirectoryMetadataResponse, error) { +func (c *internalClient) GetDirectoryMetadata(ctx context.Context, req GetDirectoryMetadataRequest, opts ...call.Option) (*GetDirectoryMetadataResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1041,7 +1057,11 @@ func (c *internalClient) GetDirectoryMetadata(ctx context.Context, req *GetDirec } pb := pathBuilder{} pb.literal("/api/2.0/fs/directories") - pb.multiSegments(*req.DirectoryPath) + if req.DirectoryPath == nil { + pb.multiSegments("") + } else { + pb.multiSegments(*req.DirectoryPath) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1082,7 +1102,7 @@ func (c *internalClient) GetDirectoryMetadata(ctx context.Context, req *GetDirec // Get the metadata of a file. The response HTTP headers contain the metadata. // There is no response body. -func (c *internalClient) GetFileMetadata(ctx context.Context, req *GetFileMetadataRequest, opts ...call.Option) (*GetFileMetadataResponse, error) { +func (c *internalClient) GetFileMetadata(ctx context.Context, req GetFileMetadataRequest, opts ...call.Option) (*GetFileMetadataResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1102,7 +1122,11 @@ func (c *internalClient) GetFileMetadata(ctx context.Context, req *GetFileMetada } pb := pathBuilder{} pb.literal("/api/2.0/fs/files") - pb.multiSegments(*req.FilePath) + if req.FilePath == nil { + pb.multiSegments("") + } else { + pb.multiSegments(*req.FilePath) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1158,8 +1182,8 @@ func (c *internalClient) GetFileMetadata(ctx context.Context, req *GetFileMetada // Returns the contents of a directory. If there is no directory at the // specified path, the API returns an HTTP 404 error. -func (c *internalClient) ListDirectoryContents(ctx context.Context, req *ListDirectoryContentsRequest, opts ...call.Option) (*ListDirectoryResponse, error) { - wireReq, err := listDirectoryContentsRequestToWire(req) +func (c *internalClient) ListDirectoryContents(ctx context.Context, req ListDirectoryContentsRequest, opts ...call.Option) (*ListDirectoryResponse, error) { + wireReq, err := listDirectoryContentsRequestToWire(&req) if err != nil { return nil, err } @@ -1176,7 +1200,11 @@ func (c *internalClient) ListDirectoryContents(ctx context.Context, req *ListDir } pb := pathBuilder{} pb.literal("/api/2.0/fs/directories") - pb.multiSegments(*req.DirectoryPath) + if req.DirectoryPath == nil { + pb.multiSegments("") + } else { + pb.multiSegments(*req.DirectoryPath) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "page_size", wireReq.PageSize); err != nil { @@ -1232,7 +1260,7 @@ func (c *internalClient) ListDirectoryContents(ctx context.Context, req *ListDir // // For example: // -// for item, err := range c.ListDirectoryContentsIter(ctx, &ListDirectoryContentsRequest{}) { +// for item, err := range c.ListDirectoryContentsIter(ctx, ListDirectoryContentsRequest{}) { // if err != nil { // return err // } @@ -1244,16 +1272,13 @@ func (c *internalClient) ListDirectoryContents(ctx context.Context, req *ListDir // // Callers who need custom pagination logic should use // ListDirectoryContents directly. -func (c *internalClient) ListDirectoryContentsIter(ctx context.Context, req *ListDirectoryContentsRequest, opts ...call.Option) iter.Seq2[*DirectoryEntry, error] { +func (c *internalClient) ListDirectoryContentsIter(ctx context.Context, req ListDirectoryContentsRequest, opts ...call.Option) iter.Seq2[*DirectoryEntry, error] { return func(yield func(*DirectoryEntry, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListDirectoryContentsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListDirectoryContents(ctx, &pageReq, opts...) + resp, err := c.ListDirectoryContents(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1276,8 +1301,8 @@ func (c *internalClient) ListDirectoryContentsIter(ctx context.Context, req *Lis // modify the bytes before sending. The contents of the resulting file will be // exactly the bytes sent in the request body. If the request is successful, // there is no response body. -func (c *internalClient) UploadFile(ctx context.Context, req *UploadFileRequest, opts ...call.Option) (*UploadFileResponse, error) { - wireReq, err := uploadFileRequestToWire(req) +func (c *internalClient) UploadFile(ctx context.Context, req UploadFileRequest, opts ...call.Option) (*UploadFileResponse, error) { + wireReq, err := uploadFileRequestToWire(&req) if err != nil { return nil, err } @@ -1294,7 +1319,11 @@ func (c *internalClient) UploadFile(ctx context.Context, req *UploadFileRequest, } pb := pathBuilder{} pb.literal("/api/2.0/fs/files") - pb.multiSegments(*req.FilePath) + if req.FilePath == nil { + pb.multiSegments("") + } else { + pb.multiSegments(*req.FilePath) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "overwrite", wireReq.Overwrite); err != nil { diff --git a/files/v2/ext_upload_test.go b/files/v2/ext_upload_test.go index f28e7ee..b98d25c 100644 --- a/files/v2/ext_upload_test.go +++ b/files/v2/ext_upload_test.go @@ -47,9 +47,10 @@ func buildUploadClient(t *testing.T, host string, hc *http.Client, workspaceID s client.WithHTTPClient(hc), client.WithCredentials(testCredentials{}), client.WithLogger(slog.New(slog.NewTextHandler(io.Discard, nil))), - // Keep tests hermetic: without this, an unset workspace ID would be - // filled from the developer's local profile. - client.WithoutProfileResolution(), + // Keep tests hermetic: without these, an unset workspace ID could be + // filled from the developer's local configuration. + client.WithoutConfigFile(), + client.WithoutEnv(), } if workspaceID != "" { opts = append(opts, client.WithWorkspaceID(workspaceID)) diff --git a/files/v2/genhelper.go b/files/v2/genhelper.go old mode 100755 new mode 100644 index 3571a65..b588598 --- a/files/v2/genhelper.go +++ b/files/v2/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/files/v2/wire.go b/files/v2/wire.go old mode 100755 new mode 100644 index 2e4e31e..2f73fbf --- a/files/v2/wire.go +++ b/files/v2/wire.go @@ -3,34 +3,88 @@ package files import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type addBlockRequestWire struct { - Handle *int64 `json:"handle,omitempty"` - Data []byte `json:"data,omitempty"` + Handle *wireInt64 `json:"handle,omitempty"` + Data []byte `json:"data,omitempty"` } func addBlockRequestToWire(v *AddBlockRequest) (*addBlockRequestWire, error) { if v == nil { return nil, nil } + handleWireValue, err := int64ToWire(v.Handle) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AddBlockRequest.Handle", err) + } return &addBlockRequestWire{ - Handle: v.Handle, + Handle: handleWireValue, Data: v.Data, }, nil } type closeRequestWire struct { - Handle *int64 `json:"handle,omitempty"` + Handle *wireInt64 `json:"handle,omitempty"` } func closeRequestToWire(v *CloseRequest) (*closeRequestWire, error) { if v == nil { return nil, nil } + handleWireValue, err := int64ToWire(v.Handle) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CloseRequest.Handle", err) + } return &closeRequestWire{ - Handle: v.Handle, + Handle: handleWireValue, }, nil } @@ -50,15 +104,19 @@ func createRequestToWire(v *CreateRequest) (*createRequestWire, error) { } type createResponseWire struct { - Handle *int64 `json:"handle,omitempty"` + Handle *wireInt64 `json:"handle,omitempty"` } func createResponseFromWire(w *createResponseWire) (*CreateResponse, error) { if w == nil { return nil, nil } + handlePublicValue, err := int64FromWire(w.Handle) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateResponse.Handle", err) + } return &CreateResponse{ - Handle: w.Handle, + Handle: handlePublicValue, }, nil } @@ -99,21 +157,29 @@ func directoryEntryFromWire(w *directoryEntryWire) (*DirectoryEntry, error) { } type fileInfoWire struct { - Path *string `json:"path,omitempty"` - IsDir *bool `json:"is_dir,omitempty"` - FileSize *int64 `json:"file_size,omitempty"` - ModificationTime *int64 `json:"modification_time,omitempty"` + Path *string `json:"path,omitempty"` + IsDir *bool `json:"is_dir,omitempty"` + FileSize *wireInt64 `json:"file_size,omitempty"` + ModificationTime *wireInt64 `json:"modification_time,omitempty"` } func fileInfoFromWire(w *fileInfoWire) (*FileInfo, error) { if w == nil { return nil, nil } + fileSizePublicValue, err := int64FromWire(w.FileSize) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FileInfo.FileSize", err) + } + modificationTimePublicValue, err := int64FromWire(w.ModificationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FileInfo.ModificationTime", err) + } return &FileInfo{ Path: w.Path, IsDir: w.IsDir, - FileSize: w.FileSize, - ModificationTime: w.ModificationTime, + FileSize: fileSizePublicValue, + ModificationTime: modificationTimePublicValue, }, nil } @@ -131,37 +197,49 @@ func getStatusRequestToWire(v *GetStatusRequest) (*getStatusRequestWire, error) } type getStatusResponseWire struct { - Path *string `json:"path,omitempty"` - IsDir *bool `json:"is_dir,omitempty"` - FileSize *int64 `json:"file_size,omitempty"` - ModificationTime *int64 `json:"modification_time,omitempty"` + Path *string `json:"path,omitempty"` + IsDir *bool `json:"is_dir,omitempty"` + FileSize *wireInt64 `json:"file_size,omitempty"` + ModificationTime *wireInt64 `json:"modification_time,omitempty"` } func getStatusResponseFromWire(w *getStatusResponseWire) (*GetStatusResponse, error) { if w == nil { return nil, nil } + fileSizePublicValue, err := int64FromWire(w.FileSize) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetStatusResponse.FileSize", err) + } + modificationTimePublicValue, err := int64FromWire(w.ModificationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetStatusResponse.ModificationTime", err) + } return &GetStatusResponse{ Path: w.Path, IsDir: w.IsDir, - FileSize: w.FileSize, - ModificationTime: w.ModificationTime, + FileSize: fileSizePublicValue, + ModificationTime: modificationTimePublicValue, }, nil } type listDirectoryContentsRequestWire struct { - DirectoryPath *string `json:"directory_path,omitempty"` - PageSize *int64 `json:"page_size,omitempty"` - PageToken *string `json:"page_token,omitempty"` + DirectoryPath *string `json:"directory_path,omitempty"` + PageSize *wireInt64 `json:"page_size,omitempty"` + PageToken *string `json:"page_token,omitempty"` } func listDirectoryContentsRequestToWire(v *ListDirectoryContentsRequest) (*listDirectoryContentsRequestWire, error) { if v == nil { return nil, nil } + pageSizeWireValue, err := int64ToWire(v.PageSize) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListDirectoryContentsRequest.PageSize", err) + } return &listDirectoryContentsRequestWire{ DirectoryPath: v.DirectoryPath, - PageSize: v.PageSize, + PageSize: pageSizeWireValue, PageToken: v.PageToken, }, nil } @@ -261,33 +339,45 @@ func putRequestToWire(v *PutRequest) (*putRequestWire, error) { } type readRequestWire struct { - Path *string `json:"path,omitempty"` - Offset *int64 `json:"offset,omitempty"` - Length *int64 `json:"length,omitempty"` + Path *string `json:"path,omitempty"` + Offset *wireInt64 `json:"offset,omitempty"` + Length *wireInt64 `json:"length,omitempty"` } func readRequestToWire(v *ReadRequest) (*readRequestWire, error) { if v == nil { return nil, nil } + offsetWireValue, err := int64ToWire(v.Offset) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ReadRequest.Offset", err) + } + lengthWireValue, err := int64ToWire(v.Length) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ReadRequest.Length", err) + } return &readRequestWire{ Path: v.Path, - Offset: v.Offset, - Length: v.Length, + Offset: offsetWireValue, + Length: lengthWireValue, }, nil } type readResponseWire struct { - BytesRead *int64 `json:"bytes_read,omitempty"` - Data []byte `json:"data,omitempty"` + BytesRead *wireInt64 `json:"bytes_read,omitempty"` + Data []byte `json:"data,omitempty"` } func readResponseFromWire(w *readResponseWire) (*ReadResponse, error) { if w == nil { return nil, nil } + bytesReadPublicValue, err := int64FromWire(w.BytesRead) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ReadResponse.BytesRead", err) + } return &ReadResponse{ - BytesRead: w.BytesRead, + BytesRead: bytesReadPublicValue, Data: w.Data, }, nil } diff --git a/forecasting/CHANGELOG.md b/forecasting/CHANGELOG.md index 6224c04..19f237c 100644 --- a/forecasting/CHANGELOG.md +++ b/forecasting/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/forecasting/go.mod b/forecasting/go.mod index b893731..fe6ca87 100644 --- a/forecasting/go.mod +++ b/forecasting/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/forecasting/internal/version.go b/forecasting/internal/version.go index 7369ac1..6837e43 100644 --- a/forecasting/internal/version.go +++ b/forecasting/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-forecasting" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/forecasting/v1/client.go b/forecasting/v1/client.go old mode 100755 new mode 100644 index 91c6ae0..eabafaf --- a/forecasting/v1/client.go +++ b/forecasting/v1/client.go @@ -76,8 +76,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Creates a serverless forecasting experiment. Returns the experiment ID. -func (c *internalClient) createForecastingExperimentBase(ctx context.Context, req *CreateForecastingExperimentRequest, opts ...call.Option) (*CreateForecastingExperimentResponse, error) { - wireReq, err := createForecastingExperimentRequestToWire(req) +func (c *internalClient) createForecastingExperimentBase(ctx context.Context, req CreateForecastingExperimentRequest, opts ...call.Option) (*CreateForecastingExperimentResponse, error) { + wireReq, err := createForecastingExperimentRequestToWire(&req) if err != nil { return nil, err } @@ -142,7 +142,7 @@ func (c *internalClient) createForecastingExperimentBase(ctx context.Context, re } // Creates a serverless forecasting experiment. Returns the experiment ID. -func (c *internalClient) CreateForecastingExperiment(ctx context.Context, req *CreateForecastingExperimentRequest, opts ...call.Option) (*CreateForecastingExperimentWaiter, error) { +func (c *internalClient) CreateForecastingExperiment(ctx context.Context, req CreateForecastingExperimentRequest, opts ...call.Option) (*CreateForecastingExperimentWaiter, error) { resp, err := c.createForecastingExperimentBase(ctx, req, opts...) if err != nil { return nil, err @@ -158,13 +158,18 @@ func (c *internalClient) CreateForecastingExperiment(ctx context.Context, req *C // CreateForecastingExperimentWaiter tracks the state of the operation started by CreateForecastingExperiment. type CreateForecastingExperimentWaiter struct { - poll func(context.Context, *GetForecastingExperimentRequest, ...call.Option) (*ForecastingExperiment, error) + poll func(context.Context, GetForecastingExperimentRequest, ...call.Option) (*ForecastingExperiment, error) experimentId string } +// GetExperimentId returns the ExperimentId value used to identify the operation. +func (w *CreateForecastingExperimentWaiter) GetExperimentId() string { + return w.experimentId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *CreateForecastingExperimentWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetForecastingExperimentRequest{ + pollResp, err := w.poll(ctx, GetForecastingExperimentRequest{ ExperimentId: &w.experimentId, }, opts...) if err != nil { @@ -189,7 +194,7 @@ func (w *CreateForecastingExperimentWaiter) Done(ctx context.Context, opts ...ca func (w *CreateForecastingExperimentWaiter) Wait(ctx context.Context, opts ...lro.Option) (*ForecastingExperiment, error) { var result *ForecastingExperiment poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetForecastingExperimentRequest{ + pollResp, err := w.poll(ctx, GetForecastingExperimentRequest{ ExperimentId: &w.experimentId, }) if err != nil { @@ -220,7 +225,7 @@ func (w *CreateForecastingExperimentWaiter) Wait(ctx context.Context, opts ...lr } // Public RPC to get forecasting experiment -func (c *internalClient) GetForecastingExperiment(ctx context.Context, req *GetForecastingExperimentRequest, opts ...call.Option) (*ForecastingExperiment, error) { +func (c *internalClient) GetForecastingExperiment(ctx context.Context, req GetForecastingExperimentRequest, opts ...call.Option) (*ForecastingExperiment, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -234,7 +239,11 @@ func (c *internalClient) GetForecastingExperiment(ctx context.Context, req *GetF } pb := pathBuilder{} pb.literal("/api/2.0/automl/get-forecasting-experiment/") - pb.singleSegment(*req.ExperimentId) + if req.ExperimentId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ExperimentId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/forecasting/v1/genhelper.go b/forecasting/v1/genhelper.go old mode 100755 new mode 100644 index 89b7b71..e85a401 --- a/forecasting/v1/genhelper.go +++ b/forecasting/v1/genhelper.go @@ -165,11 +165,12 @@ func executeWait(ctx context.Context, operation func(context.Context) error, opt ) } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -182,13 +183,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/forecasting/v1/wire.go b/forecasting/v1/wire.go old mode 100755 new mode 100644 index 169b237..3fe5e59 --- a/forecasting/v1/wire.go +++ b/forecasting/v1/wire.go @@ -2,40 +2,98 @@ package forecasting +import ( + "bytes" + "encoding/json" + "fmt" + "strconv" +) + +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type createForecastingExperimentRequestWire struct { - TrainDataPath *string `json:"train_data_path,omitempty"` - TargetColumn *string `json:"target_column,omitempty"` - TimeColumn *string `json:"time_column,omitempty"` - ForecastGranularity *string `json:"forecast_granularity,omitempty"` - ForecastHorizon *int64 `json:"forecast_horizon,omitempty"` - PrimaryMetric *string `json:"primary_metric,omitempty"` - TrainingFrameworks []string `json:"training_frameworks,omitempty"` - ExperimentPath *string `json:"experiment_path,omitempty"` - MaxRuntime *int64 `json:"max_runtime,omitempty"` - SplitColumn *string `json:"split_column,omitempty"` - CustomWeightsColumn *string `json:"custom_weights_column,omitempty"` - RegisterTo *string `json:"register_to,omitempty"` - HolidayRegions []string `json:"holiday_regions,omitempty"` - TimeseriesIdentifierColumns []string `json:"timeseries_identifier_columns,omitempty"` - PredictionDataPath *string `json:"prediction_data_path,omitempty"` - IncludeFeatures []string `json:"include_features,omitempty"` - FutureFeatureDataPath *string `json:"future_feature_data_path,omitempty"` + TrainDataPath *string `json:"train_data_path,omitempty"` + TargetColumn *string `json:"target_column,omitempty"` + TimeColumn *string `json:"time_column,omitempty"` + ForecastGranularity *string `json:"forecast_granularity,omitempty"` + ForecastHorizon *wireInt64 `json:"forecast_horizon,omitempty"` + PrimaryMetric *string `json:"primary_metric,omitempty"` + TrainingFrameworks []string `json:"training_frameworks,omitempty"` + ExperimentPath *string `json:"experiment_path,omitempty"` + MaxRuntime *wireInt64 `json:"max_runtime,omitempty"` + SplitColumn *string `json:"split_column,omitempty"` + CustomWeightsColumn *string `json:"custom_weights_column,omitempty"` + RegisterTo *string `json:"register_to,omitempty"` + HolidayRegions []string `json:"holiday_regions,omitempty"` + TimeseriesIdentifierColumns []string `json:"timeseries_identifier_columns,omitempty"` + PredictionDataPath *string `json:"prediction_data_path,omitempty"` + IncludeFeatures []string `json:"include_features,omitempty"` + FutureFeatureDataPath *string `json:"future_feature_data_path,omitempty"` } func createForecastingExperimentRequestToWire(v *CreateForecastingExperimentRequest) (*createForecastingExperimentRequestWire, error) { if v == nil { return nil, nil } + forecastHorizonWireValue, err := int64ToWire(v.ForecastHorizon) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateForecastingExperimentRequest.ForecastHorizon", err) + } + maxRuntimeWireValue, err := int64ToWire(v.MaxRuntime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateForecastingExperimentRequest.MaxRuntime", err) + } return &createForecastingExperimentRequestWire{ TrainDataPath: v.TrainDataPath, TargetColumn: v.TargetColumn, TimeColumn: v.TimeColumn, ForecastGranularity: v.ForecastGranularity, - ForecastHorizon: v.ForecastHorizon, + ForecastHorizon: forecastHorizonWireValue, PrimaryMetric: v.PrimaryMetric, TrainingFrameworks: v.TrainingFrameworks, ExperimentPath: v.ExperimentPath, - MaxRuntime: v.MaxRuntime, + MaxRuntime: maxRuntimeWireValue, SplitColumn: v.SplitColumn, CustomWeightsColumn: v.CustomWeightsColumn, RegisterTo: v.RegisterTo, diff --git a/genie/CHANGELOG.md b/genie/CHANGELOG.md index 6224c04..19f237c 100644 --- a/genie/CHANGELOG.md +++ b/genie/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/genie/go.mod b/genie/go.mod index a99d527..b08ea52 100644 --- a/genie/go.mod +++ b/genie/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/genie/internal/version.go b/genie/internal/version.go index 327b1b6..0efae7b 100644 --- a/genie/internal/version.go +++ b/genie/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-genie" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/genie/v1/client.go b/genie/v1/client.go old mode 100755 new mode 100644 index 3b2a09e..7f28442 --- a/genie/v1/client.go +++ b/genie/v1/client.go @@ -76,8 +76,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Creates a Genie space from a serialized payload. -func (c *internalClient) CreateSpace(ctx context.Context, req *GenieCreateSpaceRequest, opts ...call.Option) (*GenieSpace, error) { - wireReq, err := genieCreateSpaceRequestToWire(req) +func (c *internalClient) CreateSpace(ctx context.Context, req GenieCreateSpaceRequest, opts ...call.Option) (*GenieSpace, error) { + wireReq, err := genieCreateSpaceRequestToWire(&req) if err != nil { return nil, err } @@ -145,7 +145,7 @@ func (c *internalClient) CreateSpace(ctx context.Context, req *GenieCreateSpaceR // body is the raw PNG image, not a JSON payload. This is only available if the // attachment is a visualization and the message status is `COMPLETED`. This // endpoint is not supported for Private Link workspaces. -func (c *internalClient) DownloadMessageAttachmentVisualization(ctx context.Context, req *DownloadMessageAttachmentVisualizationRequest, opts ...call.Option) (*DownloadMessageAttachmentVisualizationResponse, error) { +func (c *internalClient) DownloadMessageAttachmentVisualization(ctx context.Context, req DownloadMessageAttachmentVisualizationRequest, opts ...call.Option) (*DownloadMessageAttachmentVisualizationResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -160,7 +160,11 @@ func (c *internalClient) DownloadMessageAttachmentVisualization(ctx context.Cont } pb := pathBuilder{} pb.literal("/api/2.0/genie/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/download-visualization") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -200,11 +204,99 @@ func (c *internalClient) DownloadMessageAttachmentVisualization(ctx context.Cont return resp, nil } +// Cancels an in-flight agent-mode response. `response_id` is the id returned in +// the `response.created` event from the agent-mode responses endpoint. The +// response stops at the next agent boundary and its terminal state is returned. +func (c *internalClient) GenieCancelResponse(ctx context.Context, req GenieCancelResponseRequest, opts ...call.Option) (*GenieMessage, error) { + wireReq, err := genieCancelResponseRequestToWire(&req) + if err != nil { + return nil, err + } + body, err := json.Marshal(wireReq) + if err != nil { + return nil, err + } + + headers := http.Header{} + headers.Set("Content-Type", "application/json") + if c.workspaceID != "" { + headers.Set("X-Databricks-Workspace-Id", c.workspaceID) + } + + baseURL, err := url.Parse(c.host) + if err != nil { + return nil, err + } + pb := pathBuilder{} + pb.literal("/api/2.0/genie/agents/") + if req.AgentId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.AgentId) + } + pb.literal("/conversations/") + if req.ConversationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ConversationId) + } + pb.literal("/responses/") + if req.ResponseId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ResponseId) + } + pb.literal("/cancel") + baseURL.Path, baseURL.RawPath = pb.build() + queryParams := url.Values{} + baseURL.RawQuery = queryParams.Encode() + urlStr := baseURL.String() + + var resp *GenieMessage + + call := func(ctx context.Context) error { + httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ + Method: "POST", + URL: urlStr, + Credentials: c.credentials, + UserAgent: c.userAgent, + Headers: headers, + Body: bytes.NewBuffer(body), + }) + if err != nil { + return err + } + + respBody, _, err := executeHTTPCall(httpCallOptions{ + req: httpReq, + client: c.httpClient, + logger: c.logger, + }) + if err != nil { + return err + } + var wireResp genieMessageWire + if err := json.Unmarshal(respBody, &wireResp); err != nil { + return err + } + resp, err = genieMessageFromWire(&wireResp) + if err != nil { + return err + } + return nil + } + + if err := executeCall(ctx, call, opts); err != nil { + return nil, err + } + return resp, nil +} + // Create new message in a [conversation](:method:genie/startconversation). The // AI response uses all previously created messages in the conversation to // respond. -func (c *internalClient) genieCreateConversationMessageBase(ctx context.Context, req *GenieCreateConversationMessageRequest, opts ...call.Option) (*GenieMessage, error) { - wireReq, err := genieCreateConversationMessageRequestToWire(req) +func (c *internalClient) genieCreateConversationMessageBase(ctx context.Context, req GenieCreateConversationMessageRequest, opts ...call.Option) (*GenieMessage, error) { + wireReq, err := genieCreateConversationMessageRequestToWire(&req) if err != nil { return nil, err } @@ -225,9 +317,17 @@ func (c *internalClient) genieCreateConversationMessageBase(ctx context.Context, } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/conversations/") - pb.singleSegment(*req.ConversationId) + if req.ConversationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ConversationId) + } pb.literal("/messages") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -277,7 +377,7 @@ func (c *internalClient) genieCreateConversationMessageBase(ctx context.Context, // Create new message in a [conversation](:method:genie/startconversation). The // AI response uses all previously created messages in the conversation to // respond. -func (c *internalClient) GenieCreateConversationMessage(ctx context.Context, req *GenieCreateConversationMessageRequest, opts ...call.Option) (*GenieCreateConversationMessageWaiter, error) { +func (c *internalClient) GenieCreateConversationMessage(ctx context.Context, req GenieCreateConversationMessageRequest, opts ...call.Option) (*GenieCreateConversationMessageWaiter, error) { if req.ConversationId == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "ConversationId") } @@ -303,15 +403,30 @@ func (c *internalClient) GenieCreateConversationMessage(ctx context.Context, req // GenieCreateConversationMessageWaiter tracks the state of the operation started by GenieCreateConversationMessage. type GenieCreateConversationMessageWaiter struct { - poll func(context.Context, *GenieGetConversationMessageRequest, ...call.Option) (*GenieMessage, error) + poll func(context.Context, GenieGetConversationMessageRequest, ...call.Option) (*GenieMessage, error) messageId string conversationId string spaceId string } +// GetMessageId returns the MessageId value used to identify the operation. +func (w *GenieCreateConversationMessageWaiter) GetMessageId() string { + return w.messageId +} + +// GetConversationId returns the ConversationId value used to identify the operation. +func (w *GenieCreateConversationMessageWaiter) GetConversationId() string { + return w.conversationId +} + +// GetSpaceId returns the SpaceId value used to identify the operation. +func (w *GenieCreateConversationMessageWaiter) GetSpaceId() string { + return w.spaceId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *GenieCreateConversationMessageWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GenieGetConversationMessageRequest{ + pollResp, err := w.poll(ctx, GenieGetConversationMessageRequest{ MessageId: &w.messageId, ConversationId: &w.conversationId, SpaceId: &w.spaceId, @@ -338,7 +453,7 @@ func (w *GenieCreateConversationMessageWaiter) Done(ctx context.Context, opts .. func (w *GenieCreateConversationMessageWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GenieMessage, error) { var result *GenieMessage poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GenieGetConversationMessageRequest{ + pollResp, err := w.poll(ctx, GenieGetConversationMessageRequest{ MessageId: &w.messageId, ConversationId: &w.conversationId, SpaceId: &w.spaceId, @@ -371,8 +486,8 @@ func (w *GenieCreateConversationMessageWaiter) Wait(ctx context.Context, opts .. } // Create and run evaluations for multiple benchmark questions in a Genie space. -func (c *internalClient) GenieCreateEvalRun(ctx context.Context, req *GenieCreateEvalRunRequest, opts ...call.Option) (*GenieEvalRunResponse, error) { - wireReq, err := genieCreateEvalRunRequestToWire(req) +func (c *internalClient) GenieCreateEvalRun(ctx context.Context, req GenieCreateEvalRunRequest, opts ...call.Option) (*GenieEvalRunResponse, error) { + wireReq, err := genieCreateEvalRunRequestToWire(&req) if err != nil { return nil, err } @@ -393,7 +508,11 @@ func (c *internalClient) GenieCreateEvalRun(ctx context.Context, req *GenieCreat } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/eval-runs") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -441,8 +560,8 @@ func (c *internalClient) GenieCreateEvalRun(ctx context.Context, req *GenieCreat } // Create a comment on a conversation message. -func (c *internalClient) GenieCreateMessageComment(ctx context.Context, req *GenieCreateMessageCommentRequest, opts ...call.Option) (*GenieMessageComment, error) { - wireReq, err := genieCreateMessageCommentRequestToWire(req) +func (c *internalClient) GenieCreateMessageComment(ctx context.Context, req GenieCreateMessageCommentRequest, opts ...call.Option) (*GenieMessageComment, error) { + wireReq, err := genieCreateMessageCommentRequestToWire(&req) if err != nil { return nil, err } @@ -463,11 +582,23 @@ func (c *internalClient) GenieCreateMessageComment(ctx context.Context, req *Gen } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/conversations/") - pb.singleSegment(*req.ConversationId) + if req.ConversationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ConversationId) + } pb.literal("/messages/") - pb.singleSegment(*req.MessageId) + if req.MessageId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MessageId) + } pb.literal("/comments") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -515,7 +646,7 @@ func (c *internalClient) GenieCreateMessageComment(ctx context.Context, req *Gen } // Delete a conversation. -func (c *internalClient) GenieDeleteConversation(ctx context.Context, req *GenieDeleteConversationRequest, opts ...call.Option) error { +func (c *internalClient) GenieDeleteConversation(ctx context.Context, req GenieDeleteConversationRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -529,9 +660,17 @@ func (c *internalClient) GenieDeleteConversation(ctx context.Context, req *Genie } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/conversations/") - pb.singleSegment(*req.ConversationId) + if req.ConversationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ConversationId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -568,7 +707,7 @@ func (c *internalClient) GenieDeleteConversation(ctx context.Context, req *Genie } // Delete a conversation message. -func (c *internalClient) GenieDeleteConversationMessage(ctx context.Context, req *GenieDeleteConversationMessageRequest, opts ...call.Option) error { +func (c *internalClient) GenieDeleteConversationMessage(ctx context.Context, req GenieDeleteConversationMessageRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -582,11 +721,23 @@ func (c *internalClient) GenieDeleteConversationMessage(ctx context.Context, req } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/conversations/") - pb.singleSegment(*req.ConversationId) + if req.ConversationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ConversationId) + } pb.literal("/messages/") - pb.singleSegment(*req.MessageId) + if req.MessageId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MessageId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -624,8 +775,8 @@ func (c *internalClient) GenieDeleteConversationMessage(ctx context.Context, req // Execute the SQL for a message query attachment. Use this API when the query // attachment has expired and needs to be re-executed. -func (c *internalClient) GenieExecuteMessageAttachmentQuery(ctx context.Context, req *GenieExecuteMessageAttachmentQueryRequest, opts ...call.Option) (*GenieGetMessageQueryResultResponse, error) { - wireReq, err := genieExecuteMessageAttachmentQueryRequestToWire(req) +func (c *internalClient) GenieExecuteMessageAttachmentQuery(ctx context.Context, req GenieExecuteMessageAttachmentQueryRequest, opts ...call.Option) (*GenieGetMessageQueryResultResponse, error) { + wireReq, err := genieExecuteMessageAttachmentQueryRequestToWire(&req) if err != nil { return nil, err } @@ -646,13 +797,29 @@ func (c *internalClient) GenieExecuteMessageAttachmentQuery(ctx context.Context, } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/conversations/") - pb.singleSegment(*req.ConversationId) + if req.ConversationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ConversationId) + } pb.literal("/messages/") - pb.singleSegment(*req.MessageId) + if req.MessageId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MessageId) + } pb.literal("/attachments/") - pb.singleSegment(*req.AttachmentId) + if req.AttachmentId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.AttachmentId) + } pb.literal("/execute-query") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -701,8 +868,8 @@ func (c *internalClient) GenieExecuteMessageAttachmentQuery(ctx context.Context, // DEPRECATED: Use [Execute Message Attachment // Query](:method:genie/executemessageattachmentquery) instead. -func (c *internalClient) GenieExecuteMessageQuery(ctx context.Context, req *GenieExecuteMessageQueryRequest, opts ...call.Option) (*GenieGetMessageQueryResultResponse, error) { - wireReq, err := genieExecuteMessageQueryRequestToWire(req) +func (c *internalClient) GenieExecuteMessageQuery(ctx context.Context, req GenieExecuteMessageQueryRequest, opts ...call.Option) (*GenieGetMessageQueryResultResponse, error) { + wireReq, err := genieExecuteMessageQueryRequestToWire(&req) if err != nil { return nil, err } @@ -723,11 +890,23 @@ func (c *internalClient) GenieExecuteMessageQuery(ctx context.Context, req *Geni } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/conversations/") - pb.singleSegment(*req.ConversationId) + if req.ConversationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ConversationId) + } pb.literal("/messages/") - pb.singleSegment(*req.MessageId) + if req.MessageId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MessageId) + } pb.literal("/execute-query") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -797,8 +976,8 @@ func (c *internalClient) GenieExecuteMessageQuery(ctx context.Context, req *Geni // details. // // ---- -func (c *internalClient) GenieGenerateDownloadFullQueryResult(ctx context.Context, req *GenieGenerateDownloadFullQueryResultRequest, opts ...call.Option) (*GenieGenerateDownloadFullQueryResultResponse, error) { - wireReq, err := genieGenerateDownloadFullQueryResultRequestToWire(req) +func (c *internalClient) GenieGenerateDownloadFullQueryResult(ctx context.Context, req GenieGenerateDownloadFullQueryResultRequest, opts ...call.Option) (*GenieGenerateDownloadFullQueryResultResponse, error) { + wireReq, err := genieGenerateDownloadFullQueryResultRequestToWire(&req) if err != nil { return nil, err } @@ -819,13 +998,29 @@ func (c *internalClient) GenieGenerateDownloadFullQueryResult(ctx context.Contex } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/conversations/") - pb.singleSegment(*req.ConversationId) + if req.ConversationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ConversationId) + } pb.literal("/messages/") - pb.singleSegment(*req.MessageId) + if req.MessageId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MessageId) + } pb.literal("/attachments/") - pb.singleSegment(*req.AttachmentId) + if req.AttachmentId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.AttachmentId) + } pb.literal("/downloads") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -873,7 +1068,7 @@ func (c *internalClient) GenieGenerateDownloadFullQueryResult(ctx context.Contex } // Get message from conversation. -func (c *internalClient) GenieGetConversationMessage(ctx context.Context, req *GenieGetConversationMessageRequest, opts ...call.Option) (*GenieMessage, error) { +func (c *internalClient) GenieGetConversationMessage(ctx context.Context, req GenieGetConversationMessageRequest, opts ...call.Option) (*GenieMessage, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -887,11 +1082,23 @@ func (c *internalClient) GenieGetConversationMessage(ctx context.Context, req *G } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/conversations/") - pb.singleSegment(*req.ConversationId) + if req.ConversationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ConversationId) + } pb.literal("/messages/") - pb.singleSegment(*req.MessageId) + if req.MessageId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MessageId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -960,8 +1167,8 @@ func (c *internalClient) GenieGetConversationMessage(ctx context.Context, req *G // details. // // ---- -func (c *internalClient) GenieGetDownloadFullQueryResult(ctx context.Context, req *GenieGetDownloadFullQueryResultRequest, opts ...call.Option) (*GenieGetDownloadFullQueryResultResponse, error) { - wireReq, err := genieGetDownloadFullQueryResultRequestToWire(req) +func (c *internalClient) GenieGetDownloadFullQueryResult(ctx context.Context, req GenieGetDownloadFullQueryResultRequest, opts ...call.Option) (*GenieGetDownloadFullQueryResultResponse, error) { + wireReq, err := genieGetDownloadFullQueryResultRequestToWire(&req) if err != nil { return nil, err } @@ -978,15 +1185,35 @@ func (c *internalClient) GenieGetDownloadFullQueryResult(ctx context.Context, re } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/conversations/") - pb.singleSegment(*req.ConversationId) + if req.ConversationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ConversationId) + } pb.literal("/messages/") - pb.singleSegment(*req.MessageId) + if req.MessageId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MessageId) + } pb.literal("/attachments/") - pb.singleSegment(*req.AttachmentId) + if req.AttachmentId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.AttachmentId) + } pb.literal("/downloads/") - pb.singleSegment(*req.DownloadId) + if req.DownloadId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DownloadId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "download_id_signature", wireReq.DownloadIdSignature); err != nil { @@ -1035,7 +1262,7 @@ func (c *internalClient) GenieGetDownloadFullQueryResult(ctx context.Context, re } // Get details for evaluation results. -func (c *internalClient) GenieGetEvalResultDetails(ctx context.Context, req *GenieGetEvalResultDetailsRequest, opts ...call.Option) (*GenieEvalResultDetails, error) { +func (c *internalClient) GenieGetEvalResultDetails(ctx context.Context, req GenieGetEvalResultDetailsRequest, opts ...call.Option) (*GenieEvalResultDetails, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1049,11 +1276,23 @@ func (c *internalClient) GenieGetEvalResultDetails(ctx context.Context, req *Gen } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/eval-runs/") - pb.singleSegment(*req.EvalRunId) + if req.EvalRunId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.EvalRunId) + } pb.literal("/results/") - pb.singleSegment(*req.ResultId) + if req.ResultId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ResultId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1099,7 +1338,7 @@ func (c *internalClient) GenieGetEvalResultDetails(ctx context.Context, req *Gen } // Get evaluation run details. -func (c *internalClient) GenieGetEvalRun(ctx context.Context, req *GenieGetEvalRunRequest, opts ...call.Option) (*GenieEvalRunResponse, error) { +func (c *internalClient) GenieGetEvalRun(ctx context.Context, req GenieGetEvalRunRequest, opts ...call.Option) (*GenieEvalRunResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1113,9 +1352,17 @@ func (c *internalClient) GenieGetEvalRun(ctx context.Context, req *GenieGetEvalR } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/eval-runs/") - pb.singleSegment(*req.EvalRunId) + if req.EvalRunId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.EvalRunId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1163,7 +1410,7 @@ func (c *internalClient) GenieGetEvalRun(ctx context.Context, req *GenieGetEvalR // Get the result of SQL query if the message has a query attachment. This is // only available if a message has a query attachment and the message status is // `EXECUTING_QUERY` OR `COMPLETED`. -func (c *internalClient) GenieGetMessageAttachmentQueryResult(ctx context.Context, req *GenieGetMessageAttachmentQueryResultRequest, opts ...call.Option) (*GenieGetMessageQueryResultResponse, error) { +func (c *internalClient) GenieGetMessageAttachmentQueryResult(ctx context.Context, req GenieGetMessageAttachmentQueryResultRequest, opts ...call.Option) (*GenieGetMessageQueryResultResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1177,13 +1424,29 @@ func (c *internalClient) GenieGetMessageAttachmentQueryResult(ctx context.Contex } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/conversations/") - pb.singleSegment(*req.ConversationId) + if req.ConversationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ConversationId) + } pb.literal("/messages/") - pb.singleSegment(*req.MessageId) + if req.MessageId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MessageId) + } pb.literal("/attachments/") - pb.singleSegment(*req.AttachmentId) + if req.AttachmentId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.AttachmentId) + } pb.literal("/query-result") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1231,7 +1494,7 @@ func (c *internalClient) GenieGetMessageAttachmentQueryResult(ctx context.Contex // DEPRECATED: Use [Get Message Attachment Query // Result](:method:genie/getmessageattachmentqueryresult) instead. -func (c *internalClient) GenieGetMessageQueryResult(ctx context.Context, req *GenieGetMessageQueryResultRequest, opts ...call.Option) (*GenieGetMessageQueryResultResponse, error) { +func (c *internalClient) GenieGetMessageQueryResult(ctx context.Context, req GenieGetMessageQueryResultRequest, opts ...call.Option) (*GenieGetMessageQueryResultResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1245,11 +1508,23 @@ func (c *internalClient) GenieGetMessageQueryResult(ctx context.Context, req *Ge } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/conversations/") - pb.singleSegment(*req.ConversationId) + if req.ConversationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ConversationId) + } pb.literal("/messages/") - pb.singleSegment(*req.MessageId) + if req.MessageId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MessageId) + } pb.literal("/query-result") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1297,7 +1572,7 @@ func (c *internalClient) GenieGetMessageQueryResult(ctx context.Context, req *Ge // DEPRECATED: Use [Get Message Attachment Query // Result](:method:genie/getmessageattachmentqueryresult) instead. -func (c *internalClient) GenieGetQueryResultByAttachment(ctx context.Context, req *GenieGetQueryResultByAttachmentRequest, opts ...call.Option) (*GenieGetMessageQueryResultResponse, error) { +func (c *internalClient) GenieGetQueryResultByAttachment(ctx context.Context, req GenieGetQueryResultByAttachmentRequest, opts ...call.Option) (*GenieGetMessageQueryResultResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1311,13 +1586,29 @@ func (c *internalClient) GenieGetQueryResultByAttachment(ctx context.Context, re } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/conversations/") - pb.singleSegment(*req.ConversationId) + if req.ConversationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ConversationId) + } pb.literal("/messages/") - pb.singleSegment(*req.MessageId) + if req.MessageId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MessageId) + } pb.literal("/query-result/") - pb.singleSegment(*req.AttachmentId) + if req.AttachmentId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.AttachmentId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1363,8 +1654,8 @@ func (c *internalClient) GenieGetQueryResultByAttachment(ctx context.Context, re } // Get details of a Genie Space. -func (c *internalClient) GenieGetSpace(ctx context.Context, req *GenieGetSpaceRequest, opts ...call.Option) (*GenieSpace, error) { - wireReq, err := genieGetSpaceRequestToWire(req) +func (c *internalClient) GenieGetSpace(ctx context.Context, req GenieGetSpaceRequest, opts ...call.Option) (*GenieSpace, error) { + wireReq, err := genieGetSpaceRequestToWire(&req) if err != nil { return nil, err } @@ -1381,7 +1672,11 @@ func (c *internalClient) GenieGetSpace(ctx context.Context, req *GenieGetSpaceRe } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "include_serialized_space", wireReq.IncludeSerializedSpace); err != nil { @@ -1430,8 +1725,8 @@ func (c *internalClient) GenieGetSpace(ctx context.Context, req *GenieGetSpaceRe } // List all comments across all messages in a conversation. -func (c *internalClient) GenieListConversationComments(ctx context.Context, req *GenieListConversationCommentsRequest, opts ...call.Option) (*GenieListConversationCommentsResponse, error) { - wireReq, err := genieListConversationCommentsRequestToWire(req) +func (c *internalClient) GenieListConversationComments(ctx context.Context, req GenieListConversationCommentsRequest, opts ...call.Option) (*GenieListConversationCommentsResponse, error) { + wireReq, err := genieListConversationCommentsRequestToWire(&req) if err != nil { return nil, err } @@ -1448,9 +1743,17 @@ func (c *internalClient) GenieListConversationComments(ctx context.Context, req } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/conversations/") - pb.singleSegment(*req.ConversationId) + if req.ConversationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ConversationId) + } pb.literal("/list-comments") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1503,8 +1806,8 @@ func (c *internalClient) GenieListConversationComments(ctx context.Context, req } // List messages in a conversation -func (c *internalClient) GenieListConversationMessages(ctx context.Context, req *GenieListConversationMessagesRequest, opts ...call.Option) (*GenieListConversationMessagesResponse, error) { - wireReq, err := genieListConversationMessagesRequestToWire(req) +func (c *internalClient) GenieListConversationMessages(ctx context.Context, req GenieListConversationMessagesRequest, opts ...call.Option) (*GenieListConversationMessagesResponse, error) { + wireReq, err := genieListConversationMessagesRequestToWire(&req) if err != nil { return nil, err } @@ -1521,9 +1824,17 @@ func (c *internalClient) GenieListConversationMessages(ctx context.Context, req } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/conversations/") - pb.singleSegment(*req.ConversationId) + if req.ConversationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ConversationId) + } pb.literal("/messages") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1576,8 +1887,8 @@ func (c *internalClient) GenieListConversationMessages(ctx context.Context, req } // Get a list of conversations in a Genie Space. -func (c *internalClient) GenieListConversations(ctx context.Context, req *GenieListConversationsRequest, opts ...call.Option) (*GenieListConversationsResponse, error) { - wireReq, err := genieListConversationsRequestToWire(req) +func (c *internalClient) GenieListConversations(ctx context.Context, req GenieListConversationsRequest, opts ...call.Option) (*GenieListConversationsResponse, error) { + wireReq, err := genieListConversationsRequestToWire(&req) if err != nil { return nil, err } @@ -1594,7 +1905,11 @@ func (c *internalClient) GenieListConversations(ctx context.Context, req *GenieL } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/conversations") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1650,8 +1965,8 @@ func (c *internalClient) GenieListConversations(ctx context.Context, req *GenieL } // List evaluation results for a specific evaluation run. -func (c *internalClient) GenieListEvalResults(ctx context.Context, req *GenieListEvalResultsRequest, opts ...call.Option) (*GenieListEvalResultsResponse, error) { - wireReq, err := genieListEvalResultsRequestToWire(req) +func (c *internalClient) GenieListEvalResults(ctx context.Context, req GenieListEvalResultsRequest, opts ...call.Option) (*GenieListEvalResultsResponse, error) { + wireReq, err := genieListEvalResultsRequestToWire(&req) if err != nil { return nil, err } @@ -1668,9 +1983,17 @@ func (c *internalClient) GenieListEvalResults(ctx context.Context, req *GenieLis } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/eval-runs/") - pb.singleSegment(*req.EvalRunId) + if req.EvalRunId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.EvalRunId) + } pb.literal("/results") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1723,8 +2046,8 @@ func (c *internalClient) GenieListEvalResults(ctx context.Context, req *GenieLis } // Lists all evaluation runs in a space. -func (c *internalClient) GenieListEvalRuns(ctx context.Context, req *GenieListEvalRunsRequest, opts ...call.Option) (*GenieListEvalRunsResponse, error) { - wireReq, err := genieListEvalRunsRequestToWire(req) +func (c *internalClient) GenieListEvalRuns(ctx context.Context, req GenieListEvalRunsRequest, opts ...call.Option) (*GenieListEvalRunsResponse, error) { + wireReq, err := genieListEvalRunsRequestToWire(&req) if err != nil { return nil, err } @@ -1741,7 +2064,11 @@ func (c *internalClient) GenieListEvalRuns(ctx context.Context, req *GenieListEv } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/eval-runs") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1794,8 +2121,8 @@ func (c *internalClient) GenieListEvalRuns(ctx context.Context, req *GenieListEv } // List comments on a specific conversation message. -func (c *internalClient) GenieListMessageComments(ctx context.Context, req *GenieListMessageCommentsRequest, opts ...call.Option) (*GenieListMessageCommentsResponse, error) { - wireReq, err := genieListMessageCommentsRequestToWire(req) +func (c *internalClient) GenieListMessageComments(ctx context.Context, req GenieListMessageCommentsRequest, opts ...call.Option) (*GenieListMessageCommentsResponse, error) { + wireReq, err := genieListMessageCommentsRequestToWire(&req) if err != nil { return nil, err } @@ -1812,11 +2139,23 @@ func (c *internalClient) GenieListMessageComments(ctx context.Context, req *Geni } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/conversations/") - pb.singleSegment(*req.ConversationId) + if req.ConversationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ConversationId) + } pb.literal("/messages/") - pb.singleSegment(*req.MessageId) + if req.MessageId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MessageId) + } pb.literal("/comments") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1869,8 +2208,8 @@ func (c *internalClient) GenieListMessageComments(ctx context.Context, req *Geni } // Get list of Genie Spaces. -func (c *internalClient) GenieListSpaces(ctx context.Context, req *GenieListSpacesRequest, opts ...call.Option) (*GenieListSpacesResponse, error) { - wireReq, err := genieListSpacesRequestToWire(req) +func (c *internalClient) GenieListSpaces(ctx context.Context, req GenieListSpacesRequest, opts ...call.Option) (*GenieListSpacesResponse, error) { + wireReq, err := genieListSpacesRequestToWire(&req) if err != nil { return nil, err } @@ -1936,8 +2275,8 @@ func (c *internalClient) GenieListSpaces(ctx context.Context, req *GenieListSpac } // Send feedback for a message. -func (c *internalClient) GenieSendMessageFeedback(ctx context.Context, req *GenieSendMessageFeedbackRequest, opts ...call.Option) error { - wireReq, err := genieSendMessageFeedbackRequestToWire(req) +func (c *internalClient) GenieSendMessageFeedback(ctx context.Context, req GenieSendMessageFeedbackRequest, opts ...call.Option) error { + wireReq, err := genieSendMessageFeedbackRequestToWire(&req) if err != nil { return err } @@ -1958,11 +2297,23 @@ func (c *internalClient) GenieSendMessageFeedback(ctx context.Context, req *Geni } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/conversations/") - pb.singleSegment(*req.ConversationId) + if req.ConversationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ConversationId) + } pb.literal("/messages/") - pb.singleSegment(*req.MessageId) + if req.MessageId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MessageId) + } pb.literal("/feedback") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -2001,8 +2352,8 @@ func (c *internalClient) GenieSendMessageFeedback(ctx context.Context, req *Geni } // Start a new conversation. -func (c *internalClient) genieStartConversationBase(ctx context.Context, req *GenieStartConversationRequest, opts ...call.Option) (*GenieStartConversationResponse, error) { - wireReq, err := genieStartConversationRequestToWire(req) +func (c *internalClient) genieStartConversationBase(ctx context.Context, req GenieStartConversationRequest, opts ...call.Option) (*GenieStartConversationResponse, error) { + wireReq, err := genieStartConversationRequestToWire(&req) if err != nil { return nil, err } @@ -2023,7 +2374,11 @@ func (c *internalClient) genieStartConversationBase(ctx context.Context, req *Ge } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } pb.literal("/start-conversation") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -2071,7 +2426,7 @@ func (c *internalClient) genieStartConversationBase(ctx context.Context, req *Ge } // Start a new conversation. -func (c *internalClient) GenieStartConversation(ctx context.Context, req *GenieStartConversationRequest, opts ...call.Option) (*GenieStartConversationWaiter, error) { +func (c *internalClient) GenieStartConversation(ctx context.Context, req GenieStartConversationRequest, opts ...call.Option) (*GenieStartConversationWaiter, error) { if req.SpaceId == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "SpaceId") } @@ -2096,15 +2451,30 @@ func (c *internalClient) GenieStartConversation(ctx context.Context, req *GenieS // GenieStartConversationWaiter tracks the state of the operation started by GenieStartConversation. type GenieStartConversationWaiter struct { - poll func(context.Context, *GenieGetConversationMessageRequest, ...call.Option) (*GenieMessage, error) + poll func(context.Context, GenieGetConversationMessageRequest, ...call.Option) (*GenieMessage, error) messageId string conversationId string spaceId string } +// GetMessageId returns the MessageId value used to identify the operation. +func (w *GenieStartConversationWaiter) GetMessageId() string { + return w.messageId +} + +// GetConversationId returns the ConversationId value used to identify the operation. +func (w *GenieStartConversationWaiter) GetConversationId() string { + return w.conversationId +} + +// GetSpaceId returns the SpaceId value used to identify the operation. +func (w *GenieStartConversationWaiter) GetSpaceId() string { + return w.spaceId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *GenieStartConversationWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GenieGetConversationMessageRequest{ + pollResp, err := w.poll(ctx, GenieGetConversationMessageRequest{ MessageId: &w.messageId, ConversationId: &w.conversationId, SpaceId: &w.spaceId, @@ -2131,7 +2501,7 @@ func (w *GenieStartConversationWaiter) Done(ctx context.Context, opts ...call.Op func (w *GenieStartConversationWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GenieMessage, error) { var result *GenieMessage poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GenieGetConversationMessageRequest{ + pollResp, err := w.poll(ctx, GenieGetConversationMessageRequest{ MessageId: &w.messageId, ConversationId: &w.conversationId, SpaceId: &w.spaceId, @@ -2164,7 +2534,7 @@ func (w *GenieStartConversationWaiter) Wait(ctx context.Context, opts ...lro.Opt } // Move a Genie Space to the trash. -func (c *internalClient) GenieTrashSpace(ctx context.Context, req *GenieTrashSpaceRequest, opts ...call.Option) error { +func (c *internalClient) GenieTrashSpace(ctx context.Context, req GenieTrashSpaceRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2178,7 +2548,11 @@ func (c *internalClient) GenieTrashSpace(ctx context.Context, req *GenieTrashSpa } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2215,8 +2589,8 @@ func (c *internalClient) GenieTrashSpace(ctx context.Context, req *GenieTrashSpa } // Updates a Genie space with a serialized payload. -func (c *internalClient) UpdateSpace(ctx context.Context, req *GenieUpdateSpaceRequest, opts ...call.Option) (*GenieSpace, error) { - wireReq, err := genieUpdateSpaceRequestToWire(req) +func (c *internalClient) UpdateSpace(ctx context.Context, req GenieUpdateSpaceRequest, opts ...call.Option) (*GenieSpace, error) { + wireReq, err := genieUpdateSpaceRequestToWire(&req) if err != nil { return nil, err } @@ -2237,7 +2611,11 @@ func (c *internalClient) UpdateSpace(ctx context.Context, req *GenieUpdateSpaceR } pb := pathBuilder{} pb.literal("/api/2.0/genie/spaces/") - pb.singleSegment(*req.SpaceId) + if req.SpaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SpaceId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/genie/v1/genhelper.go b/genie/v1/genhelper.go old mode 100755 new mode 100644 index 8e95c97..737f338 --- a/genie/v1/genhelper.go +++ b/genie/v1/genhelper.go @@ -199,11 +199,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -216,13 +217,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/genie/v1/model.go b/genie/v1/model.go old mode 100755 new mode 100644 index fcd3654..ba75728 --- a/genie/v1/model.go +++ b/genie/v1/model.go @@ -746,10 +746,9 @@ type ColumnMask struct { // column being masked and the types of the rest of the args should match the // types of columns in 'using_column_names'. UsingColumnNames []string - // The list of additional table columns or literals to be passed as additional - // arguments to a column mask function. This is the replacement of the - // deprecated using_column_names field and carries information about the types - // (alias or constant) of the arguments to the mask function. + // The list of table columns or literals to be passed as additional arguments to + // a column mask function, carrying the type (column reference vs constant + // literal) of each argument. Deprecated: use using_column_names instead. UsingArguments []PolicyFunctionArgument } @@ -855,6 +854,16 @@ type GenieAttachment_Attachment_Viz struct { func (*GenieAttachment_Attachment_Viz) isGenieAttachment_Attachment() {} +// Request to cancel an in-flight agent-mode response.. +type GenieCancelResponseRequest struct { + // The ID of the Genie agent (synonymous with the Genie space ID). + AgentId *string + // The ID of the conversation containing the response. + ConversationId *string + // The ID of the response to cancel (the id from the `response.created` event). + ResponseId *string +} + type GenieConversation struct { // Conversation ID. Legacy identifier, use conversation_id instead Id *string @@ -1577,9 +1586,9 @@ type Result struct { // Contains the result data of a single chunk when using `INLINE` disposition. // When using `EXTERNAL_LINKS` disposition, the array `external_links` is used // instead to provide URLs to the result data in cloud storage. Exactly one of -// these alternatives is used. (While the `external_links` array prepares the -// API to return multiple links in a single response. Currently only a single -// link is returned.). +// these alternatives is used. Calls to `getResultData` return the link for the +// requested chunk; `executeStatement` and `getStatementResult` responses can +// contain links for multiple chunks.. type ResultData struct { ExternalLinks []ExternalLink // The `JSON_ARRAY` format is an array of arrays of values, where each non-null diff --git a/genie/v1/wire.go b/genie/v1/wire.go old mode 100755 new mode 100644 index 92bbdb3..e0458c1 --- a/genie/v1/wire.go +++ b/genie/v1/wire.go @@ -3,29 +3,87 @@ package genie import ( + "bytes" + "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type chunkInfoWire struct { - ChunkIndex *int `json:"chunk_index,omitempty"` - RowOffset *int64 `json:"row_offset,omitempty"` - RowCount *int64 `json:"row_count,omitempty"` - ByteCount *int64 `json:"byte_count,omitempty"` - NextChunkIndex *int `json:"next_chunk_index,omitempty"` - NextChunkInternalLink *string `json:"next_chunk_internal_link,omitempty"` + ChunkIndex *int `json:"chunk_index,omitempty"` + RowOffset *wireInt64 `json:"row_offset,omitempty"` + RowCount *wireInt64 `json:"row_count,omitempty"` + ByteCount *wireInt64 `json:"byte_count,omitempty"` + NextChunkIndex *int `json:"next_chunk_index,omitempty"` + NextChunkInternalLink *string `json:"next_chunk_internal_link,omitempty"` } func chunkInfoFromWire(w *chunkInfoWire) (*ChunkInfo, error) { if w == nil { return nil, nil } + rowOffsetPublicValue, err := int64FromWire(w.RowOffset) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ChunkInfo.RowOffset", err) + } + rowCountPublicValue, err := int64FromWire(w.RowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ChunkInfo.RowCount", err) + } + byteCountPublicValue, err := int64FromWire(w.ByteCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ChunkInfo.ByteCount", err) + } return &ChunkInfo{ ChunkIndex: w.ChunkIndex, - RowOffset: w.RowOffset, - RowCount: w.RowCount, - ByteCount: w.ByteCount, + RowOffset: rowOffsetPublicValue, + RowCount: rowCountPublicValue, + ByteCount: byteCountPublicValue, NextChunkIndex: w.NextChunkIndex, NextChunkInternalLink: w.NextChunkInternalLink, }, nil @@ -113,9 +171,9 @@ type externalLinkWire struct { Expiration *string `json:"expiration,omitempty"` HttpHeaders map[string]string `json:"http_headers,omitempty"` ChunkIndex *int `json:"chunk_index,omitempty"` - RowOffset *int64 `json:"row_offset,omitempty"` - RowCount *int64 `json:"row_count,omitempty"` - ByteCount *int64 `json:"byte_count,omitempty"` + RowOffset *wireInt64 `json:"row_offset,omitempty"` + RowCount *wireInt64 `json:"row_count,omitempty"` + ByteCount *wireInt64 `json:"byte_count,omitempty"` NextChunkIndex *int `json:"next_chunk_index,omitempty"` NextChunkInternalLink *string `json:"next_chunk_internal_link,omitempty"` } @@ -124,14 +182,26 @@ func externalLinkFromWire(w *externalLinkWire) (*ExternalLink, error) { if w == nil { return nil, nil } + rowOffsetPublicValue, err := int64FromWire(w.RowOffset) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ExternalLink.RowOffset", err) + } + rowCountPublicValue, err := int64FromWire(w.RowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ExternalLink.RowCount", err) + } + byteCountPublicValue, err := int64FromWire(w.ByteCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ExternalLink.ByteCount", err) + } return &ExternalLink{ ExternalLink: w.ExternalLink, Expiration: w.Expiration, HttpHeaders: w.HttpHeaders, ChunkIndex: w.ChunkIndex, - RowOffset: w.RowOffset, - RowCount: w.RowCount, - ByteCount: w.ByteCount, + RowOffset: rowOffsetPublicValue, + RowCount: rowCountPublicValue, + ByteCount: byteCountPublicValue, NextChunkIndex: w.NextChunkIndex, NextChunkInternalLink: w.NextChunkInternalLink, }, nil @@ -198,26 +268,55 @@ func genieAttachmentFromWire(w *genieAttachmentWire) (*GenieAttachment, error) { }, nil } +type genieCancelResponseRequestWire struct { + AgentId *string `json:"agent_id,omitempty"` + ConversationId *string `json:"conversation_id,omitempty"` + ResponseId *string `json:"response_id,omitempty"` +} + +func genieCancelResponseRequestToWire(v *GenieCancelResponseRequest) (*genieCancelResponseRequestWire, error) { + if v == nil { + return nil, nil + } + return &genieCancelResponseRequestWire{ + AgentId: v.AgentId, + ConversationId: v.ConversationId, + ResponseId: v.ResponseId, + }, nil +} + type genieConversationWire struct { - Id *string `json:"id,omitempty"` - SpaceId *string `json:"space_id,omitempty"` - UserId *int64 `json:"user_id,omitempty"` - CreatedTimestamp *int64 `json:"created_timestamp,omitempty"` - LastUpdatedTimestamp *int64 `json:"last_updated_timestamp,omitempty"` - Title *string `json:"title,omitempty"` - ConversationId *string `json:"conversation_id,omitempty"` + Id *string `json:"id,omitempty"` + SpaceId *string `json:"space_id,omitempty"` + UserId *wireInt64 `json:"user_id,omitempty"` + CreatedTimestamp *wireInt64 `json:"created_timestamp,omitempty"` + LastUpdatedTimestamp *wireInt64 `json:"last_updated_timestamp,omitempty"` + Title *string `json:"title,omitempty"` + ConversationId *string `json:"conversation_id,omitempty"` } func genieConversationFromWire(w *genieConversationWire) (*GenieConversation, error) { if w == nil { return nil, nil } + userIdPublicValue, err := int64FromWire(w.UserId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenieConversation.UserId", err) + } + createdTimestampPublicValue, err := int64FromWire(w.CreatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenieConversation.CreatedTimestamp", err) + } + lastUpdatedTimestampPublicValue, err := int64FromWire(w.LastUpdatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenieConversation.LastUpdatedTimestamp", err) + } return &GenieConversation{ Id: w.Id, SpaceId: w.SpaceId, - UserId: w.UserId, - CreatedTimestamp: w.CreatedTimestamp, - LastUpdatedTimestamp: w.LastUpdatedTimestamp, + UserId: userIdPublicValue, + CreatedTimestamp: createdTimestampPublicValue, + LastUpdatedTimestamp: lastUpdatedTimestampPublicValue, Title: w.Title, ConversationId: w.ConversationId, }, nil @@ -226,7 +325,7 @@ func genieConversationFromWire(w *genieConversationWire) (*GenieConversation, er type genieConversationSummaryWire struct { ConversationId *string `json:"conversation_id,omitempty"` Title *string `json:"title,omitempty"` - CreatedTimestamp *int64 `json:"created_timestamp,omitempty"` + CreatedTimestamp *wireInt64 `json:"created_timestamp,omitempty"` AgentType GenieConversationType `json:"agent_type,omitempty"` } @@ -234,10 +333,14 @@ func genieConversationSummaryFromWire(w *genieConversationSummaryWire) (*GenieCo if w == nil { return nil, nil } + createdTimestampPublicValue, err := int64FromWire(w.CreatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenieConversationSummary.CreatedTimestamp", err) + } return &GenieConversationSummary{ ConversationId: w.ConversationId, Title: w.Title, - CreatedTimestamp: w.CreatedTimestamp, + CreatedTimestamp: createdTimestampPublicValue, AgentType: w.AgentType, }, nil } @@ -344,13 +447,17 @@ type genieEvalResultWire struct { Status EvaluationStatusType `json:"status,omitempty"` Question *string `json:"question,omitempty"` BenchmarkAnswer *string `json:"benchmark_answer,omitempty"` - CreatedByUser *int64 `json:"created_by_user,omitempty"` + CreatedByUser *wireInt64 `json:"created_by_user,omitempty"` } func genieEvalResultFromWire(w *genieEvalResultWire) (*GenieEvalResult, error) { if w == nil { return nil, nil } + createdByUserPublicValue, err := int64FromWire(w.CreatedByUser) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenieEvalResult.CreatedByUser", err) + } return &GenieEvalResult{ ResultId: w.ResultId, SpaceId: w.SpaceId, @@ -358,7 +465,7 @@ func genieEvalResultFromWire(w *genieEvalResultWire) (*GenieEvalResult, error) { Status: w.Status, Question: w.Question, BenchmarkAnswer: w.BenchmarkAnswer, - CreatedByUser: w.CreatedByUser, + CreatedByUser: createdByUserPublicValue, }, nil } @@ -402,29 +509,57 @@ func genieEvalResultDetailsFromWire(w *genieEvalResultDetailsWire) (*GenieEvalRe type genieEvalRunResponseWire struct { EvalRunId *string `json:"eval_run_id,omitempty"` EvalRunStatus EvaluationStatusType `json:"eval_run_status,omitempty"` - RunByUser *int64 `json:"run_by_user,omitempty"` - CreatedTimestamp *int64 `json:"created_timestamp,omitempty"` - NumQuestions *int64 `json:"num_questions,omitempty"` - NumCorrect *int64 `json:"num_correct,omitempty"` - NumNeedsReview *int64 `json:"num_needs_review,omitempty"` - NumDone *int64 `json:"num_done,omitempty"` - LastUpdatedTimestamp *int64 `json:"last_updated_timestamp,omitempty"` + RunByUser *wireInt64 `json:"run_by_user,omitempty"` + CreatedTimestamp *wireInt64 `json:"created_timestamp,omitempty"` + NumQuestions *wireInt64 `json:"num_questions,omitempty"` + NumCorrect *wireInt64 `json:"num_correct,omitempty"` + NumNeedsReview *wireInt64 `json:"num_needs_review,omitempty"` + NumDone *wireInt64 `json:"num_done,omitempty"` + LastUpdatedTimestamp *wireInt64 `json:"last_updated_timestamp,omitempty"` } func genieEvalRunResponseFromWire(w *genieEvalRunResponseWire) (*GenieEvalRunResponse, error) { if w == nil { return nil, nil } + runByUserPublicValue, err := int64FromWire(w.RunByUser) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenieEvalRunResponse.RunByUser", err) + } + createdTimestampPublicValue, err := int64FromWire(w.CreatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenieEvalRunResponse.CreatedTimestamp", err) + } + numQuestionsPublicValue, err := int64FromWire(w.NumQuestions) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenieEvalRunResponse.NumQuestions", err) + } + numCorrectPublicValue, err := int64FromWire(w.NumCorrect) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenieEvalRunResponse.NumCorrect", err) + } + numNeedsReviewPublicValue, err := int64FromWire(w.NumNeedsReview) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenieEvalRunResponse.NumNeedsReview", err) + } + numDonePublicValue, err := int64FromWire(w.NumDone) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenieEvalRunResponse.NumDone", err) + } + lastUpdatedTimestampPublicValue, err := int64FromWire(w.LastUpdatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenieEvalRunResponse.LastUpdatedTimestamp", err) + } return &GenieEvalRunResponse{ EvalRunId: w.EvalRunId, EvalRunStatus: w.EvalRunStatus, - RunByUser: w.RunByUser, - CreatedTimestamp: w.CreatedTimestamp, - NumQuestions: w.NumQuestions, - NumCorrect: w.NumCorrect, - NumNeedsReview: w.NumNeedsReview, - NumDone: w.NumDone, - LastUpdatedTimestamp: w.LastUpdatedTimestamp, + RunByUser: runByUserPublicValue, + CreatedTimestamp: createdTimestampPublicValue, + NumQuestions: numQuestionsPublicValue, + NumCorrect: numCorrectPublicValue, + NumNeedsReview: numNeedsReviewPublicValue, + NumDone: numDonePublicValue, + LastUpdatedTimestamp: lastUpdatedTimestampPublicValue, }, nil } @@ -851,9 +986,9 @@ type genieMessageWire struct { Id *string `json:"id,omitempty"` SpaceId *string `json:"space_id,omitempty"` ConversationId *string `json:"conversation_id,omitempty"` - UserId *int64 `json:"user_id,omitempty"` - CreatedTimestamp *int64 `json:"created_timestamp,omitempty"` - LastUpdatedTimestamp *int64 `json:"last_updated_timestamp,omitempty"` + UserId *wireInt64 `json:"user_id,omitempty"` + CreatedTimestamp *wireInt64 `json:"created_timestamp,omitempty"` + LastUpdatedTimestamp *wireInt64 `json:"last_updated_timestamp,omitempty"` Status MessageStatus_MessageStatus `json:"status,omitempty"` Content *string `json:"content,omitempty"` Attachments []genieAttachmentWire `json:"attachments,omitempty"` @@ -867,6 +1002,18 @@ func genieMessageFromWire(w *genieMessageWire) (*GenieMessage, error) { if w == nil { return nil, nil } + userIdPublicValue, err := int64FromWire(w.UserId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenieMessage.UserId", err) + } + createdTimestampPublicValue, err := int64FromWire(w.CreatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenieMessage.CreatedTimestamp", err) + } + lastUpdatedTimestampPublicValue, err := int64FromWire(w.LastUpdatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenieMessage.LastUpdatedTimestamp", err) + } attachmentsPublicValue, err := convertSlice(w.Attachments, genieAttachmentFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "GenieMessage.Attachments", err) @@ -887,9 +1034,9 @@ func genieMessageFromWire(w *genieMessageWire) (*GenieMessage, error) { Id: w.Id, SpaceId: w.SpaceId, ConversationId: w.ConversationId, - UserId: w.UserId, - CreatedTimestamp: w.CreatedTimestamp, - LastUpdatedTimestamp: w.LastUpdatedTimestamp, + UserId: userIdPublicValue, + CreatedTimestamp: createdTimestampPublicValue, + LastUpdatedTimestamp: lastUpdatedTimestampPublicValue, Status: w.Status, Content: w.Content, Attachments: attachmentsPublicValue, @@ -901,27 +1048,35 @@ func genieMessageFromWire(w *genieMessageWire) (*GenieMessage, error) { } type genieMessageCommentWire struct { - SpaceId *string `json:"space_id,omitempty"` - ConversationId *string `json:"conversation_id,omitempty"` - MessageId *string `json:"message_id,omitempty"` - MessageCommentId *string `json:"message_comment_id,omitempty"` - UserId *int64 `json:"user_id,omitempty"` - Content *string `json:"content,omitempty"` - CreatedTimestamp *int64 `json:"created_timestamp,omitempty"` + SpaceId *string `json:"space_id,omitempty"` + ConversationId *string `json:"conversation_id,omitempty"` + MessageId *string `json:"message_id,omitempty"` + MessageCommentId *string `json:"message_comment_id,omitempty"` + UserId *wireInt64 `json:"user_id,omitempty"` + Content *string `json:"content,omitempty"` + CreatedTimestamp *wireInt64 `json:"created_timestamp,omitempty"` } func genieMessageCommentFromWire(w *genieMessageCommentWire) (*GenieMessageComment, error) { if w == nil { return nil, nil } + userIdPublicValue, err := int64FromWire(w.UserId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenieMessageComment.UserId", err) + } + createdTimestampPublicValue, err := int64FromWire(w.CreatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenieMessageComment.CreatedTimestamp", err) + } return &GenieMessageComment{ SpaceId: w.SpaceId, ConversationId: w.ConversationId, MessageId: w.MessageId, MessageCommentId: w.MessageCommentId, - UserId: w.UserId, + UserId: userIdPublicValue, Content: w.Content, - CreatedTimestamp: w.CreatedTimestamp, + CreatedTimestamp: createdTimestampPublicValue, }, nil } @@ -929,7 +1084,7 @@ type genieQueryAttachmentWire struct { Title *string `json:"title,omitempty"` Query *string `json:"query,omitempty"` Description *string `json:"description,omitempty"` - LastUpdatedTimestamp *int64 `json:"last_updated_timestamp,omitempty"` + LastUpdatedTimestamp *wireInt64 `json:"last_updated_timestamp,omitempty"` Parameters []queryAttachmentParameterWire `json:"parameters,omitempty"` Id *string `json:"id,omitempty"` StatementId *string `json:"statement_id,omitempty"` @@ -941,6 +1096,10 @@ func genieQueryAttachmentFromWire(w *genieQueryAttachmentWire) (*GenieQueryAttac if w == nil { return nil, nil } + lastUpdatedTimestampPublicValue, err := int64FromWire(w.LastUpdatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenieQueryAttachment.LastUpdatedTimestamp", err) + } parametersPublicValue, err := convertSlice(w.Parameters, queryAttachmentParameterFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "GenieQueryAttachment.Parameters", err) @@ -957,7 +1116,7 @@ func genieQueryAttachmentFromWire(w *genieQueryAttachmentWire) (*GenieQueryAttac Title: w.Title, Query: w.Query, Description: w.Description, - LastUpdatedTimestamp: w.LastUpdatedTimestamp, + LastUpdatedTimestamp: lastUpdatedTimestampPublicValue, Parameters: parametersPublicValue, Id: w.Id, StatementId: w.StatementId, @@ -967,16 +1126,20 @@ func genieQueryAttachmentFromWire(w *genieQueryAttachmentWire) (*GenieQueryAttac } type genieResultMetadataWire struct { - RowCount *int64 `json:"row_count,omitempty"` - IsTruncated *bool `json:"is_truncated,omitempty"` + RowCount *wireInt64 `json:"row_count,omitempty"` + IsTruncated *bool `json:"is_truncated,omitempty"` } func genieResultMetadataFromWire(w *genieResultMetadataWire) (*GenieResultMetadata, error) { if w == nil { return nil, nil } + rowCountPublicValue, err := int64FromWire(w.RowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenieResultMetadata.RowCount", err) + } return &GenieResultMetadata{ - RowCount: w.RowCount, + RowCount: rowCountPublicValue, IsTruncated: w.IsTruncated, }, nil } @@ -1228,19 +1391,23 @@ func queryAttachmentParameterFromWire(w *queryAttachmentParameterWire) (*QueryAt } type resultWire struct { - StatementId *string `json:"statement_id,omitempty"` - RowCount *int64 `json:"row_count,omitempty"` - IsTruncated *bool `json:"is_truncated,omitempty"` - StatementIdSignature *string `json:"statement_id_signature,omitempty"` + StatementId *string `json:"statement_id,omitempty"` + RowCount *wireInt64 `json:"row_count,omitempty"` + IsTruncated *bool `json:"is_truncated,omitempty"` + StatementIdSignature *string `json:"statement_id_signature,omitempty"` } func resultFromWire(w *resultWire) (*Result, error) { if w == nil { return nil, nil } + rowCountPublicValue, err := int64FromWire(w.RowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Result.RowCount", err) + } return &Result{ StatementId: w.StatementId, - RowCount: w.RowCount, + RowCount: rowCountPublicValue, IsTruncated: w.IsTruncated, StatementIdSignature: w.StatementIdSignature, }, nil @@ -1250,9 +1417,9 @@ type resultDataWire struct { ExternalLinks []externalLinkWire `json:"external_links,omitempty"` DataArray []listValueWire `json:"data_array,omitempty"` ChunkIndex *int `json:"chunk_index,omitempty"` - RowOffset *int64 `json:"row_offset,omitempty"` - RowCount *int64 `json:"row_count,omitempty"` - ByteCount *int64 `json:"byte_count,omitempty"` + RowOffset *wireInt64 `json:"row_offset,omitempty"` + RowCount *wireInt64 `json:"row_count,omitempty"` + ByteCount *wireInt64 `json:"byte_count,omitempty"` NextChunkIndex *int `json:"next_chunk_index,omitempty"` NextChunkInternalLink *string `json:"next_chunk_internal_link,omitempty"` } @@ -1269,13 +1436,25 @@ func resultDataFromWire(w *resultDataWire) (*ResultData, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "ResultData.DataArray", err) } + rowOffsetPublicValue, err := int64FromWire(w.RowOffset) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ResultData.RowOffset", err) + } + rowCountPublicValue, err := int64FromWire(w.RowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ResultData.RowCount", err) + } + byteCountPublicValue, err := int64FromWire(w.ByteCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ResultData.ByteCount", err) + } return &ResultData{ ExternalLinks: externalLinksPublicValue, DataArray: dataArrayPublicValue, ChunkIndex: w.ChunkIndex, - RowOffset: w.RowOffset, - RowCount: w.RowCount, - ByteCount: w.ByteCount, + RowOffset: rowOffsetPublicValue, + RowCount: rowCountPublicValue, + ByteCount: byteCountPublicValue, NextChunkIndex: w.NextChunkIndex, NextChunkInternalLink: w.NextChunkInternalLink, }, nil @@ -1286,8 +1465,8 @@ type resultManifestWire struct { Schema *schemaWire `json:"schema,omitempty"` TotalChunkCount *int `json:"total_chunk_count,omitempty"` Chunks []chunkInfoWire `json:"chunks,omitempty"` - TotalRowCount *int64 `json:"total_row_count,omitempty"` - TotalByteCount *int64 `json:"total_byte_count,omitempty"` + TotalRowCount *wireInt64 `json:"total_row_count,omitempty"` + TotalByteCount *wireInt64 `json:"total_byte_count,omitempty"` Truncated *bool `json:"truncated,omitempty"` } @@ -1303,13 +1482,21 @@ func resultManifestFromWire(w *resultManifestWire) (*ResultManifest, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "ResultManifest.Chunks", err) } + totalRowCountPublicValue, err := int64FromWire(w.TotalRowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ResultManifest.TotalRowCount", err) + } + totalByteCountPublicValue, err := int64FromWire(w.TotalByteCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ResultManifest.TotalByteCount", err) + } return &ResultManifest{ Format: w.Format, Schema: schemaPublicValue, TotalChunkCount: w.TotalChunkCount, Chunks: chunksPublicValue, - TotalRowCount: w.TotalRowCount, - TotalByteCount: w.TotalByteCount, + TotalRowCount: totalRowCountPublicValue, + TotalByteCount: totalByteCountPublicValue, Truncated: w.Truncated, }, nil } diff --git a/gitcredentials/CHANGELOG.md b/gitcredentials/CHANGELOG.md index 6224c04..19f237c 100644 --- a/gitcredentials/CHANGELOG.md +++ b/gitcredentials/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/gitcredentials/go.mod b/gitcredentials/go.mod index 81582da..3dcca44 100644 --- a/gitcredentials/go.mod +++ b/gitcredentials/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/gitcredentials/internal/version.go b/gitcredentials/internal/version.go index 76c6eb9..e0c4b68 100644 --- a/gitcredentials/internal/version.go +++ b/gitcredentials/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-gitcredentials" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/gitcredentials/v1/client.go b/gitcredentials/v1/client.go old mode 100755 new mode 100644 index 210a77b..68b706f --- a/gitcredentials/v1/client.go +++ b/gitcredentials/v1/client.go @@ -75,8 +75,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Creates a Git credential entry for the user. Use the PATCH endpoint to update // existing credentials, or the DELETE endpoint to delete existing credentials. -func (c *internalClient) CreateCredentials(ctx context.Context, req *CreateCredentialsRequest, opts ...call.Option) (*CreateCredentialsResponse, error) { - wireReq, err := createCredentialsRequestToWire(req) +func (c *internalClient) CreateCredentials(ctx context.Context, req CreateCredentialsRequest, opts ...call.Option) (*CreateCredentialsResponse, error) { + wireReq, err := createCredentialsRequestToWire(&req) if err != nil { return nil, err } @@ -141,8 +141,8 @@ func (c *internalClient) CreateCredentials(ctx context.Context, req *CreateCrede } // Deletes the specified Git credential. -func (c *internalClient) DeleteCredentials(ctx context.Context, req *DeleteCredentialsRequest, opts ...call.Option) (*DeleteCredentialsResponse, error) { - wireReq, err := deleteCredentialsRequestToWire(req) +func (c *internalClient) DeleteCredentials(ctx context.Context, req DeleteCredentialsRequest, opts ...call.Option) (*DeleteCredentialsResponse, error) { + wireReq, err := deleteCredentialsRequestToWire(&req) if err != nil { return nil, err } @@ -159,7 +159,11 @@ func (c *internalClient) DeleteCredentials(ctx context.Context, req *DeleteCrede } pb := pathBuilder{} pb.literal("/api/2.0/git-credentials/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "principal_id", wireReq.PrincipalId); err != nil { @@ -202,8 +206,8 @@ func (c *internalClient) DeleteCredentials(ctx context.Context, req *DeleteCrede } // Gets the Git credential with the specified credential ID. -func (c *internalClient) GetCredentials(ctx context.Context, req *GetCredentialsRequest, opts ...call.Option) (*GetCredentialsResponse, error) { - wireReq, err := getCredentialsRequestToWire(req) +func (c *internalClient) GetCredentials(ctx context.Context, req GetCredentialsRequest, opts ...call.Option) (*GetCredentialsResponse, error) { + wireReq, err := getCredentialsRequestToWire(&req) if err != nil { return nil, err } @@ -220,7 +224,11 @@ func (c *internalClient) GetCredentials(ctx context.Context, req *GetCredentials } pb := pathBuilder{} pb.literal("/api/2.0/git-credentials/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "principal_id", wireReq.PrincipalId); err != nil { @@ -269,8 +277,8 @@ func (c *internalClient) GetCredentials(ctx context.Context, req *GetCredentials } // Lists the calling user's Git credentials. -func (c *internalClient) ListCredentials(ctx context.Context, req *ListCredentialsRequest, opts ...call.Option) (*ListCredentialsResponse, error) { - wireReq, err := listCredentialsRequestToWire(req) +func (c *internalClient) ListCredentials(ctx context.Context, req ListCredentialsRequest, opts ...call.Option) (*ListCredentialsResponse, error) { + wireReq, err := listCredentialsRequestToWire(&req) if err != nil { return nil, err } @@ -333,8 +341,8 @@ func (c *internalClient) ListCredentials(ctx context.Context, req *ListCredentia } // Updates the specified Git credential. -func (c *internalClient) UpdateCredentials(ctx context.Context, req *UpdateCredentialsRequest, opts ...call.Option) (*UpdateCredentialsResponse, error) { - wireReq, err := updateCredentialsRequestToWire(req) +func (c *internalClient) UpdateCredentials(ctx context.Context, req UpdateCredentialsRequest, opts ...call.Option) (*UpdateCredentialsResponse, error) { + wireReq, err := updateCredentialsRequestToWire(&req) if err != nil { return nil, err } @@ -355,7 +363,11 @@ func (c *internalClient) UpdateCredentials(ctx context.Context, req *UpdateCrede } pb := pathBuilder{} pb.literal("/api/2.0/git-credentials/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/gitcredentials/v1/genhelper.go b/gitcredentials/v1/genhelper.go old mode 100755 new mode 100644 index 0372533..8c875b0 --- a/gitcredentials/v1/genhelper.go +++ b/gitcredentials/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/gitcredentials/v1/wire.go b/gitcredentials/v1/wire.go old mode 100755 new mode 100644 index c8c865b..5180d4e --- a/gitcredentials/v1/wire.go +++ b/gitcredentials/v1/wire.go @@ -3,28 +3,78 @@ package gitcredentials import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type createCredentialsRequestWire struct { - GitProvider *string `json:"git_provider,omitempty"` - GitUsername *string `json:"git_username,omitempty"` - PersonalAccessToken *string `json:"personal_access_token,omitempty"` - PrincipalId *int64 `json:"principal_id,omitempty"` - Name *string `json:"name,omitempty"` - IsDefaultForProvider *bool `json:"is_default_for_provider,omitempty"` - GitEmail *string `json:"git_email,omitempty"` + GitProvider *string `json:"git_provider,omitempty"` + GitUsername *string `json:"git_username,omitempty"` + PersonalAccessToken *string `json:"personal_access_token,omitempty"` + PrincipalId *wireInt64 `json:"principal_id,omitempty"` + Name *string `json:"name,omitempty"` + IsDefaultForProvider *bool `json:"is_default_for_provider,omitempty"` + GitEmail *string `json:"git_email,omitempty"` } func createCredentialsRequestToWire(v *CreateCredentialsRequest) (*createCredentialsRequestWire, error) { if v == nil { return nil, nil } + principalIdWireValue, err := int64ToWire(v.PrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateCredentialsRequest.PrincipalId", err) + } return &createCredentialsRequestWire{ GitProvider: v.GitProvider, GitUsername: v.GitUsername, PersonalAccessToken: v.PersonalAccessToken, - PrincipalId: v.PrincipalId, + PrincipalId: principalIdWireValue, Name: v.Name, IsDefaultForProvider: v.IsDefaultForProvider, GitEmail: v.GitEmail, @@ -32,20 +82,24 @@ func createCredentialsRequestToWire(v *CreateCredentialsRequest) (*createCredent } type createCredentialsResponseWire struct { - CredentialId *int64 `json:"credential_id,omitempty"` - GitProvider *string `json:"git_provider,omitempty"` - GitUsername *string `json:"git_username,omitempty"` - Name *string `json:"name,omitempty"` - IsDefaultForProvider *bool `json:"is_default_for_provider,omitempty"` - GitEmail *string `json:"git_email,omitempty"` + CredentialId *wireInt64 `json:"credential_id,omitempty"` + GitProvider *string `json:"git_provider,omitempty"` + GitUsername *string `json:"git_username,omitempty"` + Name *string `json:"name,omitempty"` + IsDefaultForProvider *bool `json:"is_default_for_provider,omitempty"` + GitEmail *string `json:"git_email,omitempty"` } func createCredentialsResponseFromWire(w *createCredentialsResponseWire) (*CreateCredentialsResponse, error) { if w == nil { return nil, nil } + credentialIdPublicValue, err := int64FromWire(w.CredentialId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateCredentialsResponse.CredentialId", err) + } return &CreateCredentialsResponse{ - CredentialId: w.CredentialId, + CredentialId: credentialIdPublicValue, GitProvider: w.GitProvider, GitUsername: w.GitUsername, Name: w.Name, @@ -55,20 +109,24 @@ func createCredentialsResponseFromWire(w *createCredentialsResponseWire) (*Creat } type credentialWire struct { - CredentialId *int64 `json:"credential_id,omitempty"` - GitProvider *string `json:"git_provider,omitempty"` - GitUsername *string `json:"git_username,omitempty"` - Name *string `json:"name,omitempty"` - IsDefaultForProvider *bool `json:"is_default_for_provider,omitempty"` - GitEmail *string `json:"git_email,omitempty"` + CredentialId *wireInt64 `json:"credential_id,omitempty"` + GitProvider *string `json:"git_provider,omitempty"` + GitUsername *string `json:"git_username,omitempty"` + Name *string `json:"name,omitempty"` + IsDefaultForProvider *bool `json:"is_default_for_provider,omitempty"` + GitEmail *string `json:"git_email,omitempty"` } func credentialFromWire(w *credentialWire) (*Credential, error) { if w == nil { return nil, nil } + credentialIdPublicValue, err := int64FromWire(w.CredentialId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Credential.CredentialId", err) + } return &Credential{ - CredentialId: w.CredentialId, + CredentialId: credentialIdPublicValue, GitProvider: w.GitProvider, GitUsername: w.GitUsername, Name: w.Name, @@ -78,50 +136,70 @@ func credentialFromWire(w *credentialWire) (*Credential, error) { } type deleteCredentialsRequestWire struct { - Id *int64 `json:"id,omitempty"` - PrincipalId *int64 `json:"principal_id,omitempty"` + Id *wireInt64 `json:"id,omitempty"` + PrincipalId *wireInt64 `json:"principal_id,omitempty"` } func deleteCredentialsRequestToWire(v *DeleteCredentialsRequest) (*deleteCredentialsRequestWire, error) { if v == nil { return nil, nil } + idWireValue, err := int64ToWire(v.Id) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DeleteCredentialsRequest.Id", err) + } + principalIdWireValue, err := int64ToWire(v.PrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DeleteCredentialsRequest.PrincipalId", err) + } return &deleteCredentialsRequestWire{ - Id: v.Id, - PrincipalId: v.PrincipalId, + Id: idWireValue, + PrincipalId: principalIdWireValue, }, nil } type getCredentialsRequestWire struct { - Id *int64 `json:"id,omitempty"` - PrincipalId *int64 `json:"principal_id,omitempty"` + Id *wireInt64 `json:"id,omitempty"` + PrincipalId *wireInt64 `json:"principal_id,omitempty"` } func getCredentialsRequestToWire(v *GetCredentialsRequest) (*getCredentialsRequestWire, error) { if v == nil { return nil, nil } + idWireValue, err := int64ToWire(v.Id) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetCredentialsRequest.Id", err) + } + principalIdWireValue, err := int64ToWire(v.PrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetCredentialsRequest.PrincipalId", err) + } return &getCredentialsRequestWire{ - Id: v.Id, - PrincipalId: v.PrincipalId, + Id: idWireValue, + PrincipalId: principalIdWireValue, }, nil } type getCredentialsResponseWire struct { - CredentialId *int64 `json:"credential_id,omitempty"` - GitProvider *string `json:"git_provider,omitempty"` - GitUsername *string `json:"git_username,omitempty"` - Name *string `json:"name,omitempty"` - IsDefaultForProvider *bool `json:"is_default_for_provider,omitempty"` - GitEmail *string `json:"git_email,omitempty"` + CredentialId *wireInt64 `json:"credential_id,omitempty"` + GitProvider *string `json:"git_provider,omitempty"` + GitUsername *string `json:"git_username,omitempty"` + Name *string `json:"name,omitempty"` + IsDefaultForProvider *bool `json:"is_default_for_provider,omitempty"` + GitEmail *string `json:"git_email,omitempty"` } func getCredentialsResponseFromWire(w *getCredentialsResponseWire) (*GetCredentialsResponse, error) { if w == nil { return nil, nil } + credentialIdPublicValue, err := int64FromWire(w.CredentialId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetCredentialsResponse.CredentialId", err) + } return &GetCredentialsResponse{ - CredentialId: w.CredentialId, + CredentialId: credentialIdPublicValue, GitProvider: w.GitProvider, GitUsername: w.GitUsername, Name: w.Name, @@ -131,15 +209,19 @@ func getCredentialsResponseFromWire(w *getCredentialsResponseWire) (*GetCredenti } type listCredentialsRequestWire struct { - PrincipalId *int64 `json:"principal_id,omitempty"` + PrincipalId *wireInt64 `json:"principal_id,omitempty"` } func listCredentialsRequestToWire(v *ListCredentialsRequest) (*listCredentialsRequestWire, error) { if v == nil { return nil, nil } + principalIdWireValue, err := int64ToWire(v.PrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListCredentialsRequest.PrincipalId", err) + } return &listCredentialsRequestWire{ - PrincipalId: v.PrincipalId, + PrincipalId: principalIdWireValue, }, nil } @@ -161,26 +243,34 @@ func listCredentialsResponseFromWire(w *listCredentialsResponseWire) (*ListCrede } type updateCredentialsRequestWire struct { - Id *int64 `json:"id,omitempty"` - PersonalAccessToken *string `json:"personal_access_token,omitempty"` - GitProvider *string `json:"git_provider,omitempty"` - GitUsername *string `json:"git_username,omitempty"` - PrincipalId *int64 `json:"principal_id,omitempty"` - Name *string `json:"name,omitempty"` - IsDefaultForProvider *bool `json:"is_default_for_provider,omitempty"` - GitEmail *string `json:"git_email,omitempty"` + Id *wireInt64 `json:"id,omitempty"` + PersonalAccessToken *string `json:"personal_access_token,omitempty"` + GitProvider *string `json:"git_provider,omitempty"` + GitUsername *string `json:"git_username,omitempty"` + PrincipalId *wireInt64 `json:"principal_id,omitempty"` + Name *string `json:"name,omitempty"` + IsDefaultForProvider *bool `json:"is_default_for_provider,omitempty"` + GitEmail *string `json:"git_email,omitempty"` } func updateCredentialsRequestToWire(v *UpdateCredentialsRequest) (*updateCredentialsRequestWire, error) { if v == nil { return nil, nil } + idWireValue, err := int64ToWire(v.Id) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateCredentialsRequest.Id", err) + } + principalIdWireValue, err := int64ToWire(v.PrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateCredentialsRequest.PrincipalId", err) + } return &updateCredentialsRequestWire{ - Id: v.Id, + Id: idWireValue, PersonalAccessToken: v.PersonalAccessToken, GitProvider: v.GitProvider, GitUsername: v.GitUsername, - PrincipalId: v.PrincipalId, + PrincipalId: principalIdWireValue, Name: v.Name, IsDefaultForProvider: v.IsDefaultForProvider, GitEmail: v.GitEmail, diff --git a/globalinitscripts/CHANGELOG.md b/globalinitscripts/CHANGELOG.md index 6224c04..19f237c 100644 --- a/globalinitscripts/CHANGELOG.md +++ b/globalinitscripts/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/globalinitscripts/go.mod b/globalinitscripts/go.mod index 87c24be..96f9d99 100644 --- a/globalinitscripts/go.mod +++ b/globalinitscripts/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/globalinitscripts/internal/version.go b/globalinitscripts/internal/version.go index 1062753..46649fe 100644 --- a/globalinitscripts/internal/version.go +++ b/globalinitscripts/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-globalinitscripts" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/globalinitscripts/v2/client.go b/globalinitscripts/v2/client.go old mode 100755 new mode 100644 index 62f0352..c508219 --- a/globalinitscripts/v2/client.go +++ b/globalinitscripts/v2/client.go @@ -74,8 +74,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Creates a new global init script in this workspace. -func (c *internalClient) CreateGlobalInitScript(ctx context.Context, req *CreateGlobalInitScriptRequest, opts ...call.Option) (*CreateGlobalInitScriptResponse, error) { - wireReq, err := createGlobalInitScriptRequestToWire(req) +func (c *internalClient) CreateGlobalInitScript(ctx context.Context, req CreateGlobalInitScriptRequest, opts ...call.Option) (*CreateGlobalInitScriptResponse, error) { + wireReq, err := createGlobalInitScriptRequestToWire(&req) if err != nil { return nil, err } @@ -140,7 +140,7 @@ func (c *internalClient) CreateGlobalInitScript(ctx context.Context, req *Create } // Deletes a global init script. -func (c *internalClient) DeleteGlobalInitScript(ctx context.Context, req *DeleteGlobalInitScriptRequest, opts ...call.Option) (*DeleteGlobalInitScriptResponse, error) { +func (c *internalClient) DeleteGlobalInitScript(ctx context.Context, req DeleteGlobalInitScriptRequest, opts ...call.Option) (*DeleteGlobalInitScriptResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -154,7 +154,11 @@ func (c *internalClient) DeleteGlobalInitScript(ctx context.Context, req *Delete } pb := pathBuilder{} pb.literal("/api/2.0/global-init-scripts/") - pb.singleSegment(*req.ScriptId) + if req.ScriptId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ScriptId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -194,7 +198,7 @@ func (c *internalClient) DeleteGlobalInitScript(ctx context.Context, req *Delete } // Gets all the details of a script, including its Base64-encoded contents. -func (c *internalClient) GetGlobalInitScript(ctx context.Context, req *GetGlobalInitScriptRequest, opts ...call.Option) (*GlobalInitScriptDetails, error) { +func (c *internalClient) GetGlobalInitScript(ctx context.Context, req GetGlobalInitScriptRequest, opts ...call.Option) (*GlobalInitScriptDetails, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -208,7 +212,11 @@ func (c *internalClient) GetGlobalInitScript(ctx context.Context, req *GetGlobal } pb := pathBuilder{} pb.literal("/api/2.0/global-init-scripts/") - pb.singleSegment(*req.ScriptId) + if req.ScriptId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ScriptId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -257,7 +265,7 @@ func (c *internalClient) GetGlobalInitScript(ctx context.Context, req *GetGlobal // properties for each script but **not** the script contents. To retrieve the // contents of a script, use the [get a global init // script](:method:globalinitscripts/get) operation. -func (c *internalClient) ListGlobalInitScripts(ctx context.Context, req *ListGlobalInitScriptsRequest, opts ...call.Option) (*ListGlobalInitScriptsResponse, error) { +func (c *internalClient) ListGlobalInitScripts(ctx context.Context, req ListGlobalInitScriptsRequest, opts ...call.Option) (*ListGlobalInitScriptsResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -315,8 +323,8 @@ func (c *internalClient) ListGlobalInitScripts(ctx context.Context, req *ListGlo // Updates a global init script, specifying only the fields to change. All // fields are optional. Unspecified fields retain their current value. -func (c *internalClient) UpdateGlobalInitScript(ctx context.Context, req *UpdateGlobalInitScriptRequest, opts ...call.Option) (*UpdateGlobalInitScriptResponse, error) { - wireReq, err := updateGlobalInitScriptRequestToWire(req) +func (c *internalClient) UpdateGlobalInitScript(ctx context.Context, req UpdateGlobalInitScriptRequest, opts ...call.Option) (*UpdateGlobalInitScriptResponse, error) { + wireReq, err := updateGlobalInitScriptRequestToWire(&req) if err != nil { return nil, err } @@ -337,7 +345,11 @@ func (c *internalClient) UpdateGlobalInitScript(ctx context.Context, req *Update } pb := pathBuilder{} pb.literal("/api/2.0/global-init-scripts/") - pb.singleSegment(*req.ScriptId) + if req.ScriptId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ScriptId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/globalinitscripts/v2/genhelper.go b/globalinitscripts/v2/genhelper.go old mode 100755 new mode 100644 index 2427b06..a680577 --- a/globalinitscripts/v2/genhelper.go +++ b/globalinitscripts/v2/genhelper.go @@ -144,11 +144,12 @@ func executeCall(ctx context.Context, op func(context.Context) error, opts []cal return ops.Execute(ctx, op, opsOpts...) } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -161,13 +162,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/globalinitscripts/v2/wire.go b/globalinitscripts/v2/wire.go old mode 100755 new mode 100644 index e9879d3..981e758 --- a/globalinitscripts/v2/wire.go +++ b/globalinitscripts/v2/wire.go @@ -3,9 +3,55 @@ package globalinitscripts import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type createGlobalInitScriptRequestWire struct { Name *string `json:"name,omitempty"` Script []byte `json:"script,omitempty"` @@ -39,29 +85,37 @@ func createGlobalInitScriptResponseFromWire(w *createGlobalInitScriptResponseWir } type globalInitScriptDetailsWire struct { - ScriptId *string `json:"script_id,omitempty"` - Name *string `json:"name,omitempty"` - Position *int `json:"position,omitempty"` - Enabled *bool `json:"enabled,omitempty"` - CreatedBy *string `json:"created_by,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` - UpdatedBy *string `json:"updated_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + ScriptId *string `json:"script_id,omitempty"` + Name *string `json:"name,omitempty"` + Position *int `json:"position,omitempty"` + Enabled *bool `json:"enabled,omitempty"` + CreatedBy *string `json:"created_by,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` + UpdatedBy *string `json:"updated_by,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` } func globalInitScriptDetailsFromWire(w *globalInitScriptDetailsWire) (*GlobalInitScriptDetails, error) { if w == nil { return nil, nil } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GlobalInitScriptDetails.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GlobalInitScriptDetails.UpdatedAt", err) + } return &GlobalInitScriptDetails{ ScriptId: w.ScriptId, Name: w.Name, Position: w.Position, Enabled: w.Enabled, CreatedBy: w.CreatedBy, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, UpdatedBy: w.UpdatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, }, nil } diff --git a/go.work b/go.work index abec0ba..066a98a 100644 --- a/go.work +++ b/go.work @@ -21,6 +21,7 @@ use ( ./dataquality ./disasterrecovery ./environments + ./examples ./experiments ./features ./featurestore diff --git a/go.work.sum b/go.work.sum index ad22bfd..1489b7e 100644 --- a/go.work.sum +++ b/go.work.sum @@ -8,6 +8,9 @@ cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1h github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50/go.mod h1:5e1+Vvlzido69INQaVO6d87Qn543Xr6nooe9Kz7oBFM= +github.com/databricks/databricks-sdk-go v0.92.0 h1:Pvm/LvEXetOYJPgQFeewhmtkKC4z79AK3PHC5tlC+VQ= +github.com/databricks/databricks-sdk-go v0.92.0/go.mod h1:hWoHnHbNLjPKiTm5K/7bcIv3J3Pkgo5x9pPzh8K3RVE= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= @@ -16,21 +19,41 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-pkcs11 v0.2.1-0.20230907215043-c6f79328ddf9/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= +golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.182.0/go.mod h1:cGhjy4caqA5yXRzEhkHI8Y9mfyC2VLTlER2l08xaqtM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= @@ -40,3 +63,6 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240521202816-d264139d666e/go. google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/instancepools/CHANGELOG.md b/instancepools/CHANGELOG.md index 6224c04..19f237c 100644 --- a/instancepools/CHANGELOG.md +++ b/instancepools/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/instancepools/go.mod b/instancepools/go.mod index 565688d..8719e50 100644 --- a/instancepools/go.mod +++ b/instancepools/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/instancepools/internal/version.go b/instancepools/internal/version.go index e03a04d..ae987d8 100644 --- a/instancepools/internal/version.go +++ b/instancepools/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-instancepools" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/instancepools/v2/client.go b/instancepools/v2/client.go old mode 100755 new mode 100644 index b27e70d..ed9d383 --- a/instancepools/v2/client.go +++ b/instancepools/v2/client.go @@ -74,8 +74,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Creates a new instance pool using idle and ready-to-use cloud instances. -func (c *internalClient) CreateInstancePool(ctx context.Context, req *CreateInstancePoolRequest, opts ...call.Option) (*CreateInstancePoolResponse, error) { - wireReq, err := createInstancePoolRequestToWire(req) +func (c *internalClient) CreateInstancePool(ctx context.Context, req CreateInstancePoolRequest, opts ...call.Option) (*CreateInstancePoolResponse, error) { + wireReq, err := createInstancePoolRequestToWire(&req) if err != nil { return nil, err } @@ -141,8 +141,8 @@ func (c *internalClient) CreateInstancePool(ctx context.Context, req *CreateInst // Deletes the instance pool permanently. The idle instances in the pool are // terminated asynchronously. -func (c *internalClient) DeleteInstancePool(ctx context.Context, req *DeleteInstancePoolRequest, opts ...call.Option) (*DeleteInstancePoolResponse, error) { - wireReq, err := deleteInstancePoolRequestToWire(req) +func (c *internalClient) DeleteInstancePool(ctx context.Context, req DeleteInstancePoolRequest, opts ...call.Option) (*DeleteInstancePoolResponse, error) { + wireReq, err := deleteInstancePoolRequestToWire(&req) if err != nil { return nil, err } @@ -201,8 +201,8 @@ func (c *internalClient) DeleteInstancePool(ctx context.Context, req *DeleteInst } // Modifies the configuration of an existing instance pool. -func (c *internalClient) EditInstancePool(ctx context.Context, req *EditInstancePoolRequest, opts ...call.Option) (*EditInstancePoolResponse, error) { - wireReq, err := editInstancePoolRequestToWire(req) +func (c *internalClient) EditInstancePool(ctx context.Context, req EditInstancePoolRequest, opts ...call.Option) (*EditInstancePoolResponse, error) { + wireReq, err := editInstancePoolRequestToWire(&req) if err != nil { return nil, err } @@ -261,8 +261,8 @@ func (c *internalClient) EditInstancePool(ctx context.Context, req *EditInstance } // Retrieve the information for an instance pool based on its identifier. -func (c *internalClient) GetInstancePool(ctx context.Context, req *GetInstancePoolRequest, opts ...call.Option) (*GetInstancePoolResponse, error) { - wireReq, err := getInstancePoolRequestToWire(req) +func (c *internalClient) GetInstancePool(ctx context.Context, req GetInstancePoolRequest, opts ...call.Option) (*GetInstancePoolResponse, error) { + wireReq, err := getInstancePoolRequestToWire(&req) if err != nil { return nil, err } @@ -325,7 +325,7 @@ func (c *internalClient) GetInstancePool(ctx context.Context, req *GetInstancePo } // Gets a list of instance pools with their statistics. -func (c *internalClient) ListInstancePools(ctx context.Context, req *ListInstancePoolsRequest, opts ...call.Option) (*ListInstancePoolsResponse, error) { +func (c *internalClient) ListInstancePools(ctx context.Context, req ListInstancePoolsRequest, opts ...call.Option) (*ListInstancePoolsResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") diff --git a/instancepools/v2/model.go b/instancepools/v2/model.go old mode 100755 new mode 100644 index 9816ad6..f2dd36e --- a/instancepools/v2/model.go +++ b/instancepools/v2/model.go @@ -628,6 +628,9 @@ type NodeTypeFlexibility struct { // A list of node type IDs to use as fallbacks when the primary node type is // unavailable. AlternateNodeTypeIds []string + // The AWS Context ID for EC2 Fleet. When set (non-empty), the value is passed + // to AWS CreateFleet API to create the EC2 Fleet. + AwsContextId *string } // Error message of a failed pending instances. diff --git a/instancepools/v2/wire.go b/instancepools/v2/wire.go old mode 100755 new mode 100644 index c26f466..8155200 --- a/instancepools/v2/wire.go +++ b/instancepools/v2/wire.go @@ -671,6 +671,7 @@ func listInstancePoolsResponseFromWire(w *listInstancePoolsResponseWire) (*ListI type nodeTypeFlexibilityWire struct { AlternateNodeTypeIds []string `json:"alternate_node_type_ids,omitempty"` + AwsContextId *string `json:"aws_context_id,omitempty"` } func nodeTypeFlexibilityToWire(v *NodeTypeFlexibility) (*nodeTypeFlexibilityWire, error) { @@ -679,6 +680,7 @@ func nodeTypeFlexibilityToWire(v *NodeTypeFlexibility) (*nodeTypeFlexibilityWire } return &nodeTypeFlexibilityWire{ AlternateNodeTypeIds: v.AlternateNodeTypeIds, + AwsContextId: v.AwsContextId, }, nil } @@ -688,6 +690,7 @@ func nodeTypeFlexibilityFromWire(w *nodeTypeFlexibilityWire) (*NodeTypeFlexibili } return &NodeTypeFlexibility{ AlternateNodeTypeIds: w.AlternateNodeTypeIds, + AwsContextId: w.AwsContextId, }, nil } diff --git a/instanceprofiles/CHANGELOG.md b/instanceprofiles/CHANGELOG.md index 6224c04..19f237c 100644 --- a/instanceprofiles/CHANGELOG.md +++ b/instanceprofiles/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/instanceprofiles/go.mod b/instanceprofiles/go.mod index 7608779..9c91dd7 100644 --- a/instanceprofiles/go.mod +++ b/instanceprofiles/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/instanceprofiles/internal/version.go b/instanceprofiles/internal/version.go index e0da4ca..00cbb08 100644 --- a/instanceprofiles/internal/version.go +++ b/instanceprofiles/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-instanceprofiles" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/instanceprofiles/v2/client.go b/instanceprofiles/v2/client.go old mode 100755 new mode 100644 index 08e4b3b..0998790 --- a/instanceprofiles/v2/client.go +++ b/instanceprofiles/v2/client.go @@ -77,8 +77,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // users the permission to use this instance profile when launching clusters. // // This API is only available to admin users. -func (c *internalClient) AddInstanceProfile(ctx context.Context, req *AddInstanceProfileRequest, opts ...call.Option) (*AddInstanceProfileResponse, error) { - wireReq, err := addInstanceProfileRequestToWire(req) +func (c *internalClient) AddInstanceProfile(ctx context.Context, req AddInstanceProfileRequest, opts ...call.Option) (*AddInstanceProfileResponse, error) { + wireReq, err := addInstanceProfileRequestToWire(&req) if err != nil { return nil, err } @@ -148,8 +148,8 @@ func (c *internalClient) AddInstanceProfile(ctx context.Context, req *AddInstanc // serverless SQL warehouses](/sql/admin/serverless.html). // // This API is only available to admin users. -func (c *internalClient) EditInstanceProfile(ctx context.Context, req *EditInstanceProfileRequest, opts ...call.Option) (*EditInstanceProfileResponse, error) { - wireReq, err := editInstanceProfileRequestToWire(req) +func (c *internalClient) EditInstanceProfile(ctx context.Context, req EditInstanceProfileRequest, opts ...call.Option) (*EditInstanceProfileResponse, error) { + wireReq, err := editInstanceProfileRequestToWire(&req) if err != nil { return nil, err } @@ -210,7 +210,7 @@ func (c *internalClient) EditInstanceProfile(ctx context.Context, req *EditInsta // List the instance profiles that the calling user can use to launch a cluster. // // This API is available to all users. -func (c *internalClient) ListInstanceProfiles(ctx context.Context, req *ListInstanceProfilesRequest, opts ...call.Option) (*ListInstanceProfilesResponse, error) { +func (c *internalClient) ListInstanceProfiles(ctx context.Context, req ListInstanceProfilesRequest, opts ...call.Option) (*ListInstanceProfilesResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -270,8 +270,8 @@ func (c *internalClient) ListInstanceProfiles(ctx context.Context, req *ListInst // this instance profile will continue to function. // // This API is only accessible to admin users. -func (c *internalClient) RemoveInstanceProfile(ctx context.Context, req *RemoveInstanceProfileRequest, opts ...call.Option) (*RemoveInstanceProfileResponse, error) { - wireReq, err := removeInstanceProfileRequestToWire(req) +func (c *internalClient) RemoveInstanceProfile(ctx context.Context, req RemoveInstanceProfileRequest, opts ...call.Option) (*RemoveInstanceProfileResponse, error) { + wireReq, err := removeInstanceProfileRequestToWire(&req) if err != nil { return nil, err } diff --git a/jobs/CHANGELOG.md b/jobs/CHANGELOG.md index 6224c04..19f237c 100644 --- a/jobs/CHANGELOG.md +++ b/jobs/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/jobs/go.mod b/jobs/go.mod index 489ff60..86cf7ae 100644 --- a/jobs/go.mod +++ b/jobs/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/jobs/internal/version.go b/jobs/internal/version.go index 7e91ae8..8109735 100644 --- a/jobs/internal/version.go +++ b/jobs/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-jobs" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/jobs/v2/client.go b/jobs/v2/client.go old mode 100755 new mode 100644 index 3b9bebb..669d4f9 --- a/jobs/v2/client.go +++ b/jobs/v2/client.go @@ -80,8 +80,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // (specified in `new_cluster`) are compliant with the current versions of their // respective cluster policies. All-purpose clusters used in the job will not be // updated. -func (c *internalClient) EnforcePolicyComplianceForJob(ctx context.Context, req *EnforcePolicyComplianceForJob, opts ...call.Option) (*EnforcePolicyComplianceResponse, error) { - wireReq, err := enforcePolicyComplianceForJobToWire(req) +func (c *internalClient) EnforcePolicyComplianceForJob(ctx context.Context, req EnforcePolicyComplianceForJob, opts ...call.Option) (*EnforcePolicyComplianceResponse, error) { + wireReq, err := enforcePolicyComplianceForJobToWire(&req) if err != nil { return nil, err } @@ -149,8 +149,8 @@ func (c *internalClient) EnforcePolicyComplianceForJob(ctx context.Context, req // compliance if a cluster policy they use was updated after the job was last // edited and some of its job clusters no longer comply with their updated // policies. -func (c *internalClient) GetPolicyComplianceForJob(ctx context.Context, req *GetPolicyComplianceForJobRequest, opts ...call.Option) (*GetPolicyComplianceForJobResponse, error) { - wireReq, err := getPolicyComplianceForJobRequestToWire(req) +func (c *internalClient) GetPolicyComplianceForJob(ctx context.Context, req GetPolicyComplianceForJobRequest, opts ...call.Option) (*GetPolicyComplianceForJobResponse, error) { + wireReq, err := getPolicyComplianceForJobRequestToWire(&req) if err != nil { return nil, err } @@ -216,8 +216,8 @@ func (c *internalClient) GetPolicyComplianceForJob(ctx context.Context, req *Get // Jobs could be out of compliance if a cluster policy they use was updated // after the job was last edited and its job clusters no longer comply with the // updated policy. -func (c *internalClient) ListJobComplianceForPolicy(ctx context.Context, req *ListJobComplianceForPolicy, opts ...call.Option) (*ListJobComplianceResponse, error) { - wireReq, err := listJobComplianceForPolicyToWire(req) +func (c *internalClient) ListJobComplianceForPolicy(ctx context.Context, req ListJobComplianceForPolicy, opts ...call.Option) (*ListJobComplianceResponse, error) { + wireReq, err := listJobComplianceForPolicyToWire(&req) if err != nil { return nil, err } @@ -290,7 +290,7 @@ func (c *internalClient) ListJobComplianceForPolicy(ctx context.Context, req *Li // // For example: // -// for item, err := range c.ListJobComplianceForPolicyIter(ctx, &ListJobComplianceForPolicy{}) { +// for item, err := range c.ListJobComplianceForPolicyIter(ctx, ListJobComplianceForPolicy{}) { // if err != nil { // return err // } @@ -302,16 +302,13 @@ func (c *internalClient) ListJobComplianceForPolicy(ctx context.Context, req *Li // // Callers who need custom pagination logic should use // ListJobComplianceForPolicy directly. -func (c *internalClient) ListJobComplianceForPolicyIter(ctx context.Context, req *ListJobComplianceForPolicy, opts ...call.Option) iter.Seq2[*ListJobComplianceForPolicy_JobCompliance, error] { +func (c *internalClient) ListJobComplianceForPolicyIter(ctx context.Context, req ListJobComplianceForPolicy, opts ...call.Option) iter.Seq2[*ListJobComplianceForPolicy_JobCompliance, error] { return func(yield func(*ListJobComplianceForPolicy_JobCompliance, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListJobComplianceForPolicy{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListJobComplianceForPolicy(ctx, &pageReq, opts...) + resp, err := c.ListJobComplianceForPolicy(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -331,8 +328,8 @@ func (c *internalClient) ListJobComplianceForPolicyIter(ctx context.Context, req // Cancels all active runs of a job. The runs are canceled asynchronously, so it // doesn't prevent new runs from being started. -func (c *internalClient) CancelAllRuns(ctx context.Context, req *CancelAllRunsRequest, opts ...call.Option) (*CancelAllRunsResponse, error) { - wireReq, err := cancelAllRunsRequestToWire(req) +func (c *internalClient) CancelAllRuns(ctx context.Context, req CancelAllRunsRequest, opts ...call.Option) (*CancelAllRunsResponse, error) { + wireReq, err := cancelAllRunsRequestToWire(&req) if err != nil { return nil, err } @@ -392,8 +389,8 @@ func (c *internalClient) CancelAllRuns(ctx context.Context, req *CancelAllRunsRe // Cancels a job run or a task run. The run is canceled asynchronously, so it // may still be running when this request completes. -func (c *internalClient) cancelRunBase(ctx context.Context, req *CancelRunRequest, opts ...call.Option) (*CancelRunResponse, error) { - wireReq, err := cancelRunRequestToWire(req) +func (c *internalClient) cancelRunBase(ctx context.Context, req CancelRunRequest, opts ...call.Option) (*CancelRunResponse, error) { + wireReq, err := cancelRunRequestToWire(&req) if err != nil { return nil, err } @@ -453,7 +450,7 @@ func (c *internalClient) cancelRunBase(ctx context.Context, req *CancelRunReques // Cancels a job run or a task run. The run is canceled asynchronously, so it // may still be running when this request completes. -func (c *internalClient) CancelRun(ctx context.Context, req *CancelRunRequest, opts ...call.Option) (*CancelRunWaiter, error) { +func (c *internalClient) CancelRun(ctx context.Context, req CancelRunRequest, opts ...call.Option) (*CancelRunWaiter, error) { if req.RunId == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "RunId") } @@ -470,13 +467,18 @@ func (c *internalClient) CancelRun(ctx context.Context, req *CancelRunRequest, o // CancelRunWaiter tracks the state of the operation started by CancelRun. type CancelRunWaiter struct { - poll func(context.Context, *GetRunRequest, ...call.Option) (*GetRunResponse, error) + poll func(context.Context, GetRunRequest, ...call.Option) (*GetRunResponse, error) runId int64 } +// GetRunId returns the RunId value used to identify the operation. +func (w *CancelRunWaiter) GetRunId() int64 { + return w.runId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *CancelRunWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetRunRequest{ + pollResp, err := w.poll(ctx, GetRunRequest{ RunId: &w.runId, }, opts...) if err != nil { @@ -504,7 +506,7 @@ func (w *CancelRunWaiter) Done(ctx context.Context, opts ...call.Option) (bool, func (w *CancelRunWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GetRunResponse, error) { var result *GetRunResponse poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetRunRequest{ + pollResp, err := w.poll(ctx, GetRunRequest{ RunId: &w.runId, }) if err != nil { @@ -541,8 +543,8 @@ func (w *CancelRunWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GetRun } // Create a new job. -func (c *internalClient) CreateJob(ctx context.Context, req *CreateJobRequest, opts ...call.Option) (*CreateJobResponse, error) { - wireReq, err := createJobRequestToWire(req) +func (c *internalClient) CreateJob(ctx context.Context, req CreateJobRequest, opts ...call.Option) (*CreateJobResponse, error) { + wireReq, err := createJobRequestToWire(&req) if err != nil { return nil, err } @@ -607,8 +609,8 @@ func (c *internalClient) CreateJob(ctx context.Context, req *CreateJobRequest, o } // Deletes a job. -func (c *internalClient) DeleteJob(ctx context.Context, req *DeleteJobRequest, opts ...call.Option) (*DeleteJobResponse, error) { - wireReq, err := deleteJobRequestToWire(req) +func (c *internalClient) DeleteJob(ctx context.Context, req DeleteJobRequest, opts ...call.Option) (*DeleteJobResponse, error) { + wireReq, err := deleteJobRequestToWire(&req) if err != nil { return nil, err } @@ -667,8 +669,8 @@ func (c *internalClient) DeleteJob(ctx context.Context, req *DeleteJobRequest, o } // Deletes a non-active run. Returns an error if the run is active. -func (c *internalClient) DeleteRun(ctx context.Context, req *DeleteRunRequest, opts ...call.Option) (*DeleteRunResponse, error) { - wireReq, err := deleteRunRequestToWire(req) +func (c *internalClient) DeleteRun(ctx context.Context, req DeleteRunRequest, opts ...call.Option) (*DeleteRunResponse, error) { + wireReq, err := deleteRunRequestToWire(&req) if err != nil { return nil, err } @@ -727,8 +729,8 @@ func (c *internalClient) DeleteRun(ctx context.Context, req *DeleteRunRequest, o } // Export and retrieve the job run task. -func (c *internalClient) ExportRun(ctx context.Context, req *ExportRunRequest, opts ...call.Option) (*ExportRunResponse, error) { - wireReq, err := exportRunRequestToWire(req) +func (c *internalClient) ExportRun(ctx context.Context, req ExportRunRequest, opts ...call.Option) (*ExportRunResponse, error) { + wireReq, err := exportRunRequestToWire(&req) if err != nil { return nil, err } @@ -805,8 +807,8 @@ func (c *internalClient) ExportRun(ctx context.Context, req *ExportRunRequest, o // requests. If any array properties have more than 100 elements, additional // results will be returned on subsequent requests. Arrays without additional // results will be empty on later pages. -func (c *internalClient) GetJob(ctx context.Context, req *GetJobRequest, opts ...call.Option) (*GetJobResponse, error) { - wireReq, err := getJobRequestToWire(req) +func (c *internalClient) GetJob(ctx context.Context, req GetJobRequest, opts ...call.Option) (*GetJobResponse, error) { + wireReq, err := getJobRequestToWire(&req) if err != nil { return nil, err } @@ -884,8 +886,8 @@ func (c *internalClient) GetJob(ctx context.Context, req *GetJobRequest, opts .. // requests. If any array properties have more than 100 elements, additional // results will be returned on subsequent requests. Arrays without additional // results will be empty on later pages. -func (c *internalClient) GetRun(ctx context.Context, req *GetRunRequest, opts ...call.Option) (*GetRunResponse, error) { - wireReq, err := getRunRequestToWire(req) +func (c *internalClient) GetRun(ctx context.Context, req GetRunRequest, opts ...call.Option) (*GetRunResponse, error) { + wireReq, err := getRunRequestToWire(&req) if err != nil { return nil, err } @@ -966,8 +968,8 @@ func (c *internalClient) GetRun(ctx context.Context, req *GetRunRequest, opts .. // HTTP status code 400 if the __run_id__ parameter is invalid. Runs are // automatically removed after 60 days. If you to want to reference them beyond // 60 days, you must save old run results before they expire. -func (c *internalClient) GetRunOutput(ctx context.Context, req *GetRunOutputRequest, opts ...call.Option) (*GetRunOutputResponse, error) { - wireReq, err := getRunOutputRequestToWire(req) +func (c *internalClient) GetRunOutput(ctx context.Context, req GetRunOutputRequest, opts ...call.Option) (*GetRunOutputResponse, error) { + wireReq, err := getRunOutputRequestToWire(&req) if err != nil { return nil, err } @@ -1030,8 +1032,8 @@ func (c *internalClient) GetRunOutput(ctx context.Context, req *GetRunOutputRequ } // Retrieves a list of jobs. -func (c *internalClient) ListJobs(ctx context.Context, req *ListJobsRequest, opts ...call.Option) (*ListJobsResponse, error) { - wireReq, err := listJobsRequestToWire(req) +func (c *internalClient) ListJobs(ctx context.Context, req ListJobsRequest, opts ...call.Option) (*ListJobsResponse, error) { + wireReq, err := listJobsRequestToWire(&req) if err != nil { return nil, err } @@ -1110,7 +1112,7 @@ func (c *internalClient) ListJobs(ctx context.Context, req *ListJobsRequest, opt // // For example: // -// for item, err := range c.ListJobsIter(ctx, &ListJobsRequest{}) { +// for item, err := range c.ListJobsIter(ctx, ListJobsRequest{}) { // if err != nil { // return err // } @@ -1122,16 +1124,13 @@ func (c *internalClient) ListJobs(ctx context.Context, req *ListJobsRequest, opt // // Callers who need custom pagination logic should use // ListJobs directly. -func (c *internalClient) ListJobsIter(ctx context.Context, req *ListJobsRequest, opts ...call.Option) iter.Seq2[*BaseJob, error] { +func (c *internalClient) ListJobsIter(ctx context.Context, req ListJobsRequest, opts ...call.Option) iter.Seq2[*BaseJob, error] { return func(yield func(*BaseJob, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListJobsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListJobs(ctx, &pageReq, opts...) + resp, err := c.ListJobs(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1151,8 +1150,8 @@ func (c *internalClient) ListJobsIter(ctx context.Context, req *ListJobsRequest, // List runs in descending order by end time. If a run has not finished, it // falls back to start time. -func (c *internalClient) ListRuns(ctx context.Context, req *ListRunsRequest, opts ...call.Option) (*ListRunsResponse, error) { - wireReq, err := listRunsRequestToWire(req) +func (c *internalClient) ListRuns(ctx context.Context, req ListRunsRequest, opts ...call.Option) (*ListRunsResponse, error) { + wireReq, err := listRunsRequestToWire(&req) if err != nil { return nil, err } @@ -1248,7 +1247,7 @@ func (c *internalClient) ListRuns(ctx context.Context, req *ListRunsRequest, opt // // For example: // -// for item, err := range c.ListRunsIter(ctx, &ListRunsRequest{}) { +// for item, err := range c.ListRunsIter(ctx, ListRunsRequest{}) { // if err != nil { // return err // } @@ -1260,16 +1259,13 @@ func (c *internalClient) ListRuns(ctx context.Context, req *ListRunsRequest, opt // // Callers who need custom pagination logic should use // ListRuns directly. -func (c *internalClient) ListRunsIter(ctx context.Context, req *ListRunsRequest, opts ...call.Option) iter.Seq2[*BaseRun, error] { +func (c *internalClient) ListRunsIter(ctx context.Context, req ListRunsRequest, opts ...call.Option) iter.Seq2[*BaseRun, error] { return func(yield func(*BaseRun, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListRunsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListRuns(ctx, &pageReq, opts...) + resp, err := c.ListRuns(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1290,8 +1286,8 @@ func (c *internalClient) ListRunsIter(ctx context.Context, req *ListRunsRequest, // Re-run one or more tasks. Tasks are re-run as part of the original job run. // They use the current job and task settings, and can be viewed in the history // for the original job run. -func (c *internalClient) repairBase(ctx context.Context, req *RepairRunRequest, opts ...call.Option) (*RepairRunResponse, error) { - wireReq, err := repairRunRequestToWire(req) +func (c *internalClient) repairBase(ctx context.Context, req RepairRunRequest, opts ...call.Option) (*RepairRunResponse, error) { + wireReq, err := repairRunRequestToWire(&req) if err != nil { return nil, err } @@ -1358,7 +1354,7 @@ func (c *internalClient) repairBase(ctx context.Context, req *RepairRunRequest, // Re-run one or more tasks. Tasks are re-run as part of the original job run. // They use the current job and task settings, and can be viewed in the history // for the original job run. -func (c *internalClient) Repair(ctx context.Context, req *RepairRunRequest, opts ...call.Option) (*RepairWaiter, error) { +func (c *internalClient) Repair(ctx context.Context, req RepairRunRequest, opts ...call.Option) (*RepairWaiter, error) { if req.RunId == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "RunId") } @@ -1375,13 +1371,18 @@ func (c *internalClient) Repair(ctx context.Context, req *RepairRunRequest, opts // RepairWaiter tracks the state of the operation started by Repair. type RepairWaiter struct { - poll func(context.Context, *GetRunRequest, ...call.Option) (*GetRunResponse, error) + poll func(context.Context, GetRunRequest, ...call.Option) (*GetRunResponse, error) runId int64 } +// GetRunId returns the RunId value used to identify the operation. +func (w *RepairWaiter) GetRunId() int64 { + return w.runId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *RepairWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetRunRequest{ + pollResp, err := w.poll(ctx, GetRunRequest{ RunId: &w.runId, }, opts...) if err != nil { @@ -1409,7 +1410,7 @@ func (w *RepairWaiter) Done(ctx context.Context, opts ...call.Option) (bool, err func (w *RepairWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GetRunResponse, error) { var result *GetRunResponse poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetRunRequest{ + pollResp, err := w.poll(ctx, GetRunRequest{ RunId: &w.runId, }) if err != nil { @@ -1447,8 +1448,8 @@ func (w *RepairWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GetRunRes // Overwrite all settings for the given job. Use the [_Update_ // endpoint](:method:jobs/update) to update job settings partially. -func (c *internalClient) ResetJob(ctx context.Context, req *ResetJobRequest, opts ...call.Option) (*ResetJobResponse, error) { - wireReq, err := resetJobRequestToWire(req) +func (c *internalClient) ResetJob(ctx context.Context, req ResetJobRequest, opts ...call.Option) (*ResetJobResponse, error) { + wireReq, err := resetJobRequestToWire(&req) if err != nil { return nil, err } @@ -1507,8 +1508,8 @@ func (c *internalClient) ResetJob(ctx context.Context, req *ResetJobRequest, opt } // Run a job and return the `run_id` of the triggered run. -func (c *internalClient) runNowBase(ctx context.Context, req *RunNowRequest, opts ...call.Option) (*RunNowResponse, error) { - wireReq, err := runNowRequestToWire(req) +func (c *internalClient) runNowBase(ctx context.Context, req RunNowRequest, opts ...call.Option) (*RunNowResponse, error) { + wireReq, err := runNowRequestToWire(&req) if err != nil { return nil, err } @@ -1573,7 +1574,7 @@ func (c *internalClient) runNowBase(ctx context.Context, req *RunNowRequest, opt } // Run a job and return the `run_id` of the triggered run. -func (c *internalClient) RunNow(ctx context.Context, req *RunNowRequest, opts ...call.Option) (*RunNowWaiter, error) { +func (c *internalClient) RunNow(ctx context.Context, req RunNowRequest, opts ...call.Option) (*RunNowWaiter, error) { resp, err := c.runNowBase(ctx, req, opts...) if err != nil { return nil, err @@ -1589,13 +1590,18 @@ func (c *internalClient) RunNow(ctx context.Context, req *RunNowRequest, opts .. // RunNowWaiter tracks the state of the operation started by RunNow. type RunNowWaiter struct { - poll func(context.Context, *GetRunRequest, ...call.Option) (*GetRunResponse, error) + poll func(context.Context, GetRunRequest, ...call.Option) (*GetRunResponse, error) runId int64 } +// GetRunId returns the RunId value used to identify the operation. +func (w *RunNowWaiter) GetRunId() int64 { + return w.runId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *RunNowWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetRunRequest{ + pollResp, err := w.poll(ctx, GetRunRequest{ RunId: &w.runId, }, opts...) if err != nil { @@ -1623,7 +1629,7 @@ func (w *RunNowWaiter) Done(ctx context.Context, opts ...call.Option) (bool, err func (w *RunNowWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GetRunResponse, error) { var result *GetRunResponse poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetRunRequest{ + pollResp, err := w.poll(ctx, GetRunRequest{ RunId: &w.runId, }) if err != nil { @@ -1671,8 +1677,8 @@ func (w *RunNowWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GetRunRes // specify the compute needs for the job. Alternatively, use the `POST // /jobs/create` and `POST /jobs/run-now` endpoints to create and run a saved // job. -func (c *internalClient) submitRunBase(ctx context.Context, req *SubmitRunRequest, opts ...call.Option) (*SubmitRunResponse, error) { - wireReq, err := submitRunRequestToWire(req) +func (c *internalClient) submitRunBase(ctx context.Context, req SubmitRunRequest, opts ...call.Option) (*SubmitRunResponse, error) { + wireReq, err := submitRunRequestToWire(&req) if err != nil { return nil, err } @@ -1748,7 +1754,7 @@ func (c *internalClient) submitRunBase(ctx context.Context, req *SubmitRunReques // specify the compute needs for the job. Alternatively, use the `POST // /jobs/create` and `POST /jobs/run-now` endpoints to create and run a saved // job. -func (c *internalClient) SubmitRun(ctx context.Context, req *SubmitRunRequest, opts ...call.Option) (*SubmitRunWaiter, error) { +func (c *internalClient) SubmitRun(ctx context.Context, req SubmitRunRequest, opts ...call.Option) (*SubmitRunWaiter, error) { resp, err := c.submitRunBase(ctx, req, opts...) if err != nil { return nil, err @@ -1764,13 +1770,18 @@ func (c *internalClient) SubmitRun(ctx context.Context, req *SubmitRunRequest, o // SubmitRunWaiter tracks the state of the operation started by SubmitRun. type SubmitRunWaiter struct { - poll func(context.Context, *GetRunRequest, ...call.Option) (*GetRunResponse, error) + poll func(context.Context, GetRunRequest, ...call.Option) (*GetRunResponse, error) runId int64 } +// GetRunId returns the RunId value used to identify the operation. +func (w *SubmitRunWaiter) GetRunId() int64 { + return w.runId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *SubmitRunWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetRunRequest{ + pollResp, err := w.poll(ctx, GetRunRequest{ RunId: &w.runId, }, opts...) if err != nil { @@ -1798,7 +1809,7 @@ func (w *SubmitRunWaiter) Done(ctx context.Context, opts ...call.Option) (bool, func (w *SubmitRunWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GetRunResponse, error) { var result *GetRunResponse poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetRunRequest{ + pollResp, err := w.poll(ctx, GetRunRequest{ RunId: &w.runId, }) if err != nil { @@ -1836,8 +1847,8 @@ func (w *SubmitRunWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GetRun // Add, update, or remove specific settings of an existing job. Use the [_Reset_ // endpoint](:method:jobs/reset) to overwrite all job settings. -func (c *internalClient) UpdateJob(ctx context.Context, req *UpdateJobRequest, opts ...call.Option) (*UpdateJobResponse, error) { - wireReq, err := updateJobRequestToWire(req) +func (c *internalClient) UpdateJob(ctx context.Context, req UpdateJobRequest, opts ...call.Option) (*UpdateJobResponse, error) { + wireReq, err := updateJobRequestToWire(&req) if err != nil { return nil, err } diff --git a/jobs/v2/model.go b/jobs/v2/model.go old mode 100755 new mode 100644 index 9553bfc..0d3fb82 --- a/jobs/v2/model.go +++ b/jobs/v2/model.go @@ -140,6 +140,27 @@ const ( DataSecurityMode_DataSecurityModeAuto DataSecurityMode = "DATA_SECURITY_MODE_AUTO" ) +// Days of week that can be referenced by Jobs scheduling settings. +type DayOfWeek string + +const ( + DayOfWeek_Unspecified DayOfWeek = "" + // The day of week is Monday. + DayOfWeek_Monday DayOfWeek = "MONDAY" + // The day of week is Tuesday. + DayOfWeek_Tuesday DayOfWeek = "TUESDAY" + // The day of week is Wednesday. + DayOfWeek_Wednesday DayOfWeek = "WEDNESDAY" + // The day of week is Thursday. + DayOfWeek_Thursday DayOfWeek = "THURSDAY" + // The day of week is Friday. + DayOfWeek_Friday DayOfWeek = "FRIDAY" + // The day of week is Saturday. + DayOfWeek_Saturday DayOfWeek = "SATURDAY" + // The day of week is Sunday. + DayOfWeek_Sunday DayOfWeek = "SUNDAY" +) + // Response enumeration from calling the dbt platform API, for inclusion in // output type DbtPlatformRunStatus string @@ -215,6 +236,10 @@ const ( HardwareAcceleratorType_Gpu1xA10 HardwareAcceleratorType = "GPU_1xA10" // GPU_8xH100: 8x H100 GPU configuration. HardwareAcceleratorType_Gpu8xH100 HardwareAcceleratorType = "GPU_8xH100" + // GPU_1xH100: Single H100 GPU configuration. + HardwareAcceleratorType_Gpu1xH100 HardwareAcceleratorType = "GPU_1xH100" + // GPU_8xB300: 8x B300 GPU configuration. + HardwareAcceleratorType_Gpu8xB300 HardwareAcceleratorType = "GPU_8xB300" ) // Edit mode of the job. @@ -948,6 +973,14 @@ type AlertTask struct { // The subscribers receive alert evaluation result notifications after the alert // task is completed. The number of subscriptions is limited to 100. Subscribers []AlertTaskSubscriber + // Per-run parameter overrides, keyed by parameter name, applied onto the + // alert's stored query parameters before the query is executed. Only scalar + // values are supported. Values may reference job parameters with + // `{{job.parameters.*}}`, which are resolved before the task runs. An override + // whose key does not match a stored parameter fails the task run. Limited to + // 10000 characters when serialized as JSON; keys must be 1-100 characters and + // contain only letters, digits, underscores, dashes, and periods. + Parameters map[string]string } type AlertTaskOutput struct { @@ -1578,7 +1611,7 @@ type ClusterSpec_NewCluster struct { // Currently only supported for GCP HYPERDISK_BALANCED disks. RemoteDiskThroughput *int // If set, what the total initial volume size (in GB) of the remote disks should - // be. Currently only supported for GCP HYPERDISK_BALANCED disks. + // be. Supported for GCP. TotalInitialRemoteDiskSize *int // Controls dependency configuration for the cluster. DependencyMode DependencyMode @@ -1641,6 +1674,11 @@ type ComputeSpec struct { // `GPU_8xH100` with `accelerator_count: 16` allocates 2 nodes (8 GPUs per // node). AcceleratorCount *int + // Optional ID of a pre-provisioned accelerator capacity reservation to run this + // AI Runtime workload on. When set, the workload is scheduled onto the + // referenced reserved capacity instead of the on-demand capacity shared among + // all customers. + ProvisionedCapacityId *string } type ConditionTask struct { @@ -1673,6 +1711,9 @@ type ContinuousSettings struct { // Indicate whether the continuous job is applying task level retries or not. // Defaults to NEVER. TaskRetryMode TaskRetryMode + // Defines when platform-initiated maintenance may run for this job. If + // unspecified, maintenance may run at any time. + MaintenanceWindow *MaintenanceWindow } // Continuous trigger. Stripped-down counterpart to `ContinuousSettings`: @@ -1681,6 +1722,9 @@ type ContinuousSettings struct { type ContinuousTriggerConfiguration struct { // Whether the continuous job applies task-level retries. Defaults to NEVER. TaskRetryMode TaskRetryMode + // Defines when platform-initiated maintenance may run for this trigger. If + // unspecified, maintenance may run at any time. + MaintenanceWindow *MaintenanceWindow } type ContinuousTriggerState struct { @@ -3343,6 +3387,23 @@ type LogAnalyticsInfo struct { LogAnalyticsPrimaryKey *string } +// A recurring weekly time window during which platform-initiated maintenance is +// allowed to run for a continuous job.. +type MaintenanceWindow struct { + // An integer between 0 and 23 denoting the start hour for the maintenance + // window in the 24-hour day. Platform-initiated maintenance is triggered only + // within a one-hour window starting at this hour. This field is required. + StartHour *int + // The day of week on which maintenance is allowed to happen. This field is + // required. + DayOfWeek DayOfWeek + // A Java timezone ID. The maintenance window is resolved with respect to this + // timezone. See [Java TimeZone] for details. This field is required. + // + // [Java TimeZone]: https://docs.oracle.com/javase/7/docs/api/java/util/TimeZone.html + TimezoneId *string +} + type MavenLibrary struct { // Gradle-style maven coordinates. For example: "org.jsoup:jsoup:1.7.2". Coordinates *string @@ -3388,6 +3449,9 @@ type NodeTypeFlexibility struct { // A list of node type IDs to use as fallbacks when the primary node type is // unavailable. AlternateNodeTypeIds []string + // The AWS Context ID for EC2 Fleet. When set (non-empty), the value is passed + // to AWS CreateFleet API to create the EC2 Fleet. + AwsContextId *string } type NotebookTask struct { @@ -3466,7 +3530,7 @@ type OutputSchemaInfo struct { // one variant matching the corresponding trigger's type. Variants with no // runtime state today (`schedule`, `model`) are emitted as empty messages.. type PerTriggerState struct { - // (-- Next ID: 9. --) Runtime-state variant for the corresponding trigger; + // (-- Next ID: 10. --) Runtime-state variant for the corresponding trigger; // exactly one field is set, matching the trigger's type in // `TriggerConfiguration`. TriggerType isPerTriggerState_TriggerType @@ -5934,10 +5998,10 @@ type TerminationType struct { // A single trigger attached to a job via `JobSettings.triggers`. Exactly one of // the trigger-type fields (`periodic`, `schedule`, `continuous`, -// `file_arrival`, `table_update`, `model`) must be set; mutual exclusivity is -// enforced in the API handler rather than via `oneof` so that codegen, -// validation, and JSON serialization across SDKs and Terraform behave -// consistently.. +// `file_arrival`, `table_update`, `model`, `job_completion`) must be set; +// mutual exclusivity is enforced in the API handler rather than via `oneof` so +// that codegen, validation, and JSON serialization across SDKs and Terraform +// behave consistently.. type TriggerConfiguration struct { // Whether this trigger is paused. Defaults to UNPAUSED when unset; the server // always returns an explicit value on read. @@ -6036,7 +6100,7 @@ type TriggerSettings_Configuration_Model struct { func (*TriggerSettings_Configuration_Model) isTriggerSettings_Configuration() {} type TriggerState struct { - // (-- Next ID: 7. --) + // (-- Next ID: 8. --) TriggerType isTriggerState_TriggerType // State for SQL condition evaluation, can coexist with other trigger states. SqlCondition *SqlConditionState diff --git a/jobs/v2/wire.go b/jobs/v2/wire.go old mode 100755 new mode 100644 index 86c1370..7199ec6 --- a/jobs/v2/wire.go +++ b/jobs/v2/wire.go @@ -3,9 +3,55 @@ package jobs import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type accessControlRequestWire struct { UserName *string `json:"user_name,omitempty"` GroupName *string `json:"group_name,omitempty"` @@ -137,6 +183,7 @@ type alertTaskWire struct { WarehouseId *string `json:"warehouse_id,omitempty"` WorkspacePath *string `json:"workspace_path,omitempty"` Subscribers []alertTaskSubscriberWire `json:"subscribers,omitempty"` + Parameters map[string]string `json:"parameters,omitempty"` } func alertTaskToWire(v *AlertTask) (*alertTaskWire, error) { @@ -152,6 +199,7 @@ func alertTaskToWire(v *AlertTask) (*alertTaskWire, error) { WarehouseId: v.WarehouseId, WorkspacePath: v.WorkspacePath, Subscribers: subscribersWireValue, + Parameters: v.Parameters, }, nil } @@ -168,6 +216,7 @@ func alertTaskFromWire(w *alertTaskWire) (*AlertTask, error) { WarehouseId: w.WarehouseId, WorkspacePath: w.WorkspacePath, Subscribers: subscribersPublicValue, + Parameters: w.Parameters, }, nil } @@ -357,11 +406,11 @@ func azureAttributesFromWire(w *azureAttributesWire) (*AzureAttributes, error) { } type baseJobWire struct { - JobId *int64 `json:"job_id,omitempty"` + JobId *wireInt64 `json:"job_id,omitempty"` CreatorUserName *string `json:"creator_user_name,omitempty"` RunAsUserName *string `json:"run_as_user_name,omitempty"` Settings *jobSettingsWire `json:"settings,omitempty"` - CreatedTime *int64 `json:"created_time,omitempty"` + CreatedTime *wireInt64 `json:"created_time,omitempty"` TriggerState *triggerStateWire `json:"trigger_state,omitempty"` HasMore *bool `json:"has_more,omitempty"` EffectiveBudgetPolicyId *string `json:"effective_budget_policy_id,omitempty"` @@ -373,10 +422,18 @@ func baseJobFromWire(w *baseJobWire) (*BaseJob, error) { if w == nil { return nil, nil } + jobIdPublicValue, err := int64FromWire(w.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BaseJob.JobId", err) + } settingsPublicValue, err := jobSettingsFromWire(w.Settings) if err != nil { return nil, fmt.Errorf("%s: %w", "BaseJob.Settings", err) } + createdTimePublicValue, err := int64FromWire(w.CreatedTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BaseJob.CreatedTime", err) + } triggerStatePublicValue, err := triggerStateFromWire(w.TriggerState) if err != nil { return nil, fmt.Errorf("%s: %w", "BaseJob.TriggerState", err) @@ -386,11 +443,11 @@ func baseJobFromWire(w *baseJobWire) (*BaseJob, error) { return nil, fmt.Errorf("%s: %w", "BaseJob.TriggerDetails", err) } return &BaseJob{ - JobId: w.JobId, + JobId: jobIdPublicValue, CreatorUserName: w.CreatorUserName, RunAsUserName: w.RunAsUserName, Settings: settingsPublicValue, - CreatedTime: w.CreatedTime, + CreatedTime: createdTimePublicValue, TriggerState: triggerStatePublicValue, HasMore: w.HasMore, EffectiveBudgetPolicyId: w.EffectiveBudgetPolicyId, @@ -400,11 +457,11 @@ func baseJobFromWire(w *baseJobWire) (*BaseJob, error) { } type baseRunWire struct { - JobId *int64 `json:"job_id,omitempty"` - RunId *int64 `json:"run_id,omitempty"` + JobId *wireInt64 `json:"job_id,omitempty"` + RunId *wireInt64 `json:"run_id,omitempty"` CreatorUserName *string `json:"creator_user_name,omitempty"` - NumberInJob *int64 `json:"number_in_job,omitempty"` - OriginalAttemptRunId *int64 `json:"original_attempt_run_id,omitempty"` + NumberInJob *wireInt64 `json:"number_in_job,omitempty"` + OriginalAttemptRunId *wireInt64 `json:"original_attempt_run_id,omitempty"` State *runStateWire `json:"state,omitempty"` Schedule *cronScheduleWire `json:"schedule,omitempty"` ClusterSpec *clusterSpecWire `json:"cluster_spec,omitempty"` @@ -423,25 +480,41 @@ type baseRunWire struct { GitSource *gitSourceWire `json:"git_source,omitempty"` RepairHistory []repairWire `json:"repair_history,omitempty"` Status *runStatusWire `json:"status,omitempty"` - JobRunId *int64 `json:"job_run_id,omitempty"` + JobRunId *wireInt64 `json:"job_run_id,omitempty"` HasMore *bool `json:"has_more,omitempty"` EffectivePerformanceTarget PerformanceTarget_PerformanceTarget `json:"effective_performance_target,omitempty"` EffectiveUsagePolicyId *string `json:"effective_usage_policy_id,omitempty"` DeploymentId *string `json:"deployment_id,omitempty"` VersionId *string `json:"version_id,omitempty"` - StartTime *int64 `json:"start_time,omitempty"` - SetupDuration *int64 `json:"setup_duration,omitempty"` - ExecutionDuration *int64 `json:"execution_duration,omitempty"` - CleanupDuration *int64 `json:"cleanup_duration,omitempty"` - EndTime *int64 `json:"end_time,omitempty"` - RunDuration *int64 `json:"run_duration,omitempty"` - QueueDuration *int64 `json:"queue_duration,omitempty"` + StartTime *wireInt64 `json:"start_time,omitempty"` + SetupDuration *wireInt64 `json:"setup_duration,omitempty"` + ExecutionDuration *wireInt64 `json:"execution_duration,omitempty"` + CleanupDuration *wireInt64 `json:"cleanup_duration,omitempty"` + EndTime *wireInt64 `json:"end_time,omitempty"` + RunDuration *wireInt64 `json:"run_duration,omitempty"` + QueueDuration *wireInt64 `json:"queue_duration,omitempty"` } func baseRunFromWire(w *baseRunWire) (*BaseRun, error) { if w == nil { return nil, nil } + jobIdPublicValue, err := int64FromWire(w.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BaseRun.JobId", err) + } + runIdPublicValue, err := int64FromWire(w.RunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BaseRun.RunId", err) + } + numberInJobPublicValue, err := int64FromWire(w.NumberInJob) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BaseRun.NumberInJob", err) + } + originalAttemptRunIdPublicValue, err := int64FromWire(w.OriginalAttemptRunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BaseRun.OriginalAttemptRunId", err) + } statePublicValue, err := runStateFromWire(w.State) if err != nil { return nil, fmt.Errorf("%s: %w", "BaseRun.State", err) @@ -490,12 +563,44 @@ func baseRunFromWire(w *baseRunWire) (*BaseRun, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "BaseRun.Status", err) } + jobRunIdPublicValue, err := int64FromWire(w.JobRunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BaseRun.JobRunId", err) + } + startTimePublicValue, err := int64FromWire(w.StartTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BaseRun.StartTime", err) + } + setupDurationPublicValue, err := int64FromWire(w.SetupDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BaseRun.SetupDuration", err) + } + executionDurationPublicValue, err := int64FromWire(w.ExecutionDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BaseRun.ExecutionDuration", err) + } + cleanupDurationPublicValue, err := int64FromWire(w.CleanupDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BaseRun.CleanupDuration", err) + } + endTimePublicValue, err := int64FromWire(w.EndTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BaseRun.EndTime", err) + } + runDurationPublicValue, err := int64FromWire(w.RunDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BaseRun.RunDuration", err) + } + queueDurationPublicValue, err := int64FromWire(w.QueueDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BaseRun.QueueDuration", err) + } return &BaseRun{ - JobId: w.JobId, - RunId: w.RunId, + JobId: jobIdPublicValue, + RunId: runIdPublicValue, CreatorUserName: w.CreatorUserName, - NumberInJob: w.NumberInJob, - OriginalAttemptRunId: w.OriginalAttemptRunId, + NumberInJob: numberInJobPublicValue, + OriginalAttemptRunId: originalAttemptRunIdPublicValue, State: statePublicValue, Schedule: schedulePublicValue, ClusterSpec: clusterSpecPublicValue, @@ -514,47 +619,55 @@ func baseRunFromWire(w *baseRunWire) (*BaseRun, error) { GitSource: gitSourcePublicValue, RepairHistory: repairHistoryPublicValue, Status: statusPublicValue, - JobRunId: w.JobRunId, + JobRunId: jobRunIdPublicValue, HasMore: w.HasMore, EffectivePerformanceTarget: w.EffectivePerformanceTarget, EffectiveUsagePolicyId: w.EffectiveUsagePolicyId, DeploymentId: w.DeploymentId, VersionId: w.VersionId, - StartTime: w.StartTime, - SetupDuration: w.SetupDuration, - ExecutionDuration: w.ExecutionDuration, - CleanupDuration: w.CleanupDuration, - EndTime: w.EndTime, - RunDuration: w.RunDuration, - QueueDuration: w.QueueDuration, + StartTime: startTimePublicValue, + SetupDuration: setupDurationPublicValue, + ExecutionDuration: executionDurationPublicValue, + CleanupDuration: cleanupDurationPublicValue, + EndTime: endTimePublicValue, + RunDuration: runDurationPublicValue, + QueueDuration: queueDurationPublicValue, }, nil } type cancelAllRunsRequestWire struct { - JobId *int64 `json:"job_id,omitempty"` - AllQueuedRuns *bool `json:"all_queued_runs,omitempty"` + JobId *wireInt64 `json:"job_id,omitempty"` + AllQueuedRuns *bool `json:"all_queued_runs,omitempty"` } func cancelAllRunsRequestToWire(v *CancelAllRunsRequest) (*cancelAllRunsRequestWire, error) { if v == nil { return nil, nil } + jobIdWireValue, err := int64ToWire(v.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CancelAllRunsRequest.JobId", err) + } return &cancelAllRunsRequestWire{ - JobId: v.JobId, + JobId: jobIdWireValue, AllQueuedRuns: v.AllQueuedRuns, }, nil } type cancelRunRequestWire struct { - RunId *int64 `json:"run_id,omitempty"` + RunId *wireInt64 `json:"run_id,omitempty"` } func cancelRunRequestToWire(v *CancelRunRequest) (*cancelRunRequestWire, error) { if v == nil { return nil, nil } + runIdWireValue, err := int64ToWire(v.RunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CancelRunRequest.RunId", err) + } return &cancelRunRequestWire{ - RunId: v.RunId, + RunId: runIdWireValue, }, nil } @@ -1073,8 +1186,9 @@ func computeConfigFromWire(w *computeConfigWire) (*ComputeConfig, error) { } type computeSpecWire struct { - AcceleratorType ComputeSpec_AcceleratorType `json:"accelerator_type,omitempty"` - AcceleratorCount *int `json:"accelerator_count,omitempty"` + AcceleratorType ComputeSpec_AcceleratorType `json:"accelerator_type,omitempty"` + AcceleratorCount *int `json:"accelerator_count,omitempty"` + ProvisionedCapacityId *string `json:"provisioned_capacity_id,omitempty"` } func computeSpecToWire(v *ComputeSpec) (*computeSpecWire, error) { @@ -1082,8 +1196,9 @@ func computeSpecToWire(v *ComputeSpec) (*computeSpecWire, error) { return nil, nil } return &computeSpecWire{ - AcceleratorType: v.AcceleratorType, - AcceleratorCount: v.AcceleratorCount, + AcceleratorType: v.AcceleratorType, + AcceleratorCount: v.AcceleratorCount, + ProvisionedCapacityId: v.ProvisionedCapacityId, }, nil } @@ -1092,8 +1207,9 @@ func computeSpecFromWire(w *computeSpecWire) (*ComputeSpec, error) { return nil, nil } return &ComputeSpec{ - AcceleratorType: w.AcceleratorType, - AcceleratorCount: w.AcceleratorCount, + AcceleratorType: w.AcceleratorType, + AcceleratorCount: w.AcceleratorCount, + ProvisionedCapacityId: w.ProvisionedCapacityId, }, nil } @@ -1129,17 +1245,23 @@ func conditionTaskFromWire(w *conditionTaskWire) (*ConditionTask, error) { } type continuousSettingsWire struct { - PauseStatus SchedulePauseStatus `json:"pause_status,omitempty"` - TaskRetryMode TaskRetryMode `json:"task_retry_mode,omitempty"` + PauseStatus SchedulePauseStatus `json:"pause_status,omitempty"` + TaskRetryMode TaskRetryMode `json:"task_retry_mode,omitempty"` + MaintenanceWindow *maintenanceWindowWire `json:"maintenance_window,omitempty"` } func continuousSettingsToWire(v *ContinuousSettings) (*continuousSettingsWire, error) { if v == nil { return nil, nil } + maintenanceWindowWireValue, err := maintenanceWindowToWire(v.MaintenanceWindow) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ContinuousSettings.MaintenanceWindow", err) + } return &continuousSettingsWire{ - PauseStatus: v.PauseStatus, - TaskRetryMode: v.TaskRetryMode, + PauseStatus: v.PauseStatus, + TaskRetryMode: v.TaskRetryMode, + MaintenanceWindow: maintenanceWindowWireValue, }, nil } @@ -1147,22 +1269,33 @@ func continuousSettingsFromWire(w *continuousSettingsWire) (*ContinuousSettings, if w == nil { return nil, nil } + maintenanceWindowPublicValue, err := maintenanceWindowFromWire(w.MaintenanceWindow) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ContinuousSettings.MaintenanceWindow", err) + } return &ContinuousSettings{ - PauseStatus: w.PauseStatus, - TaskRetryMode: w.TaskRetryMode, + PauseStatus: w.PauseStatus, + TaskRetryMode: w.TaskRetryMode, + MaintenanceWindow: maintenanceWindowPublicValue, }, nil } type continuousTriggerConfigurationWire struct { - TaskRetryMode TaskRetryMode `json:"task_retry_mode,omitempty"` + TaskRetryMode TaskRetryMode `json:"task_retry_mode,omitempty"` + MaintenanceWindow *maintenanceWindowWire `json:"maintenance_window,omitempty"` } func continuousTriggerConfigurationToWire(v *ContinuousTriggerConfiguration) (*continuousTriggerConfigurationWire, error) { if v == nil { return nil, nil } + maintenanceWindowWireValue, err := maintenanceWindowToWire(v.MaintenanceWindow) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ContinuousTriggerConfiguration.MaintenanceWindow", err) + } return &continuousTriggerConfigurationWire{ - TaskRetryMode: v.TaskRetryMode, + TaskRetryMode: v.TaskRetryMode, + MaintenanceWindow: maintenanceWindowWireValue, }, nil } @@ -1170,24 +1303,33 @@ func continuousTriggerConfigurationFromWire(w *continuousTriggerConfigurationWir if w == nil { return nil, nil } + maintenanceWindowPublicValue, err := maintenanceWindowFromWire(w.MaintenanceWindow) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ContinuousTriggerConfiguration.MaintenanceWindow", err) + } return &ContinuousTriggerConfiguration{ - TaskRetryMode: w.TaskRetryMode, + TaskRetryMode: w.TaskRetryMode, + MaintenanceWindow: maintenanceWindowPublicValue, }, nil } type continuousTriggerStateWire struct { - ConsecutiveFailures *int `json:"consecutive_failures,omitempty"` - NextAttemptMs *int64 `json:"next_attempt_ms,omitempty"` - IsBackingOff *bool `json:"is_backing_off,omitempty"` + ConsecutiveFailures *int `json:"consecutive_failures,omitempty"` + NextAttemptMs *wireInt64 `json:"next_attempt_ms,omitempty"` + IsBackingOff *bool `json:"is_backing_off,omitempty"` } func continuousTriggerStateFromWire(w *continuousTriggerStateWire) (*ContinuousTriggerState, error) { if w == nil { return nil, nil } + nextAttemptMsPublicValue, err := int64FromWire(w.NextAttemptMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ContinuousTriggerState.NextAttemptMs", err) + } return &ContinuousTriggerState{ ConsecutiveFailures: w.ConsecutiveFailures, - NextAttemptMs: w.NextAttemptMs, + NextAttemptMs: nextAttemptMsPublicValue, IsBackingOff: w.IsBackingOff, }, nil } @@ -1336,15 +1478,19 @@ func createJobRequestToWire(v *CreateJobRequest) (*createJobRequestWire, error) } type createJobResponseWire struct { - JobId *int64 `json:"job_id,omitempty"` + JobId *wireInt64 `json:"job_id,omitempty"` } func createJobResponseFromWire(w *createJobResponseWire) (*CreateJobResponse, error) { if w == nil { return nil, nil } + jobIdPublicValue, err := int64FromWire(w.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateJobResponse.JobId", err) + } return &CreateJobResponse{ - JobId: w.JobId, + JobId: jobIdPublicValue, }, nil } @@ -1529,16 +1675,20 @@ func dbtCloudJobRunStepFromWire(w *dbtCloudJobRunStepWire) (*DbtCloudJobRunStep, } type dbtCloudTaskWire struct { - DbtCloudJobId *int64 `json:"dbt_cloud_job_id,omitempty"` - ConnectionResourceName *string `json:"connection_resource_name,omitempty"` + DbtCloudJobId *wireInt64 `json:"dbt_cloud_job_id,omitempty"` + ConnectionResourceName *string `json:"connection_resource_name,omitempty"` } func dbtCloudTaskToWire(v *DbtCloudTask) (*dbtCloudTaskWire, error) { if v == nil { return nil, nil } + dbtCloudJobIdWireValue, err := int64ToWire(v.DbtCloudJobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DbtCloudTask.DbtCloudJobId", err) + } return &dbtCloudTaskWire{ - DbtCloudJobId: v.DbtCloudJobId, + DbtCloudJobId: dbtCloudJobIdWireValue, ConnectionResourceName: v.ConnectionResourceName, }, nil } @@ -1547,14 +1697,18 @@ func dbtCloudTaskFromWire(w *dbtCloudTaskWire) (*DbtCloudTask, error) { if w == nil { return nil, nil } + dbtCloudJobIdPublicValue, err := int64FromWire(w.DbtCloudJobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DbtCloudTask.DbtCloudJobId", err) + } return &DbtCloudTask{ - DbtCloudJobId: w.DbtCloudJobId, + DbtCloudJobId: dbtCloudJobIdPublicValue, ConnectionResourceName: w.ConnectionResourceName, }, nil } type dbtCloudTaskOutputWire struct { - DbtCloudJobRunId *int64 `json:"dbt_cloud_job_run_id,omitempty"` + DbtCloudJobRunId *wireInt64 `json:"dbt_cloud_job_run_id,omitempty"` DbtCloudJobRunUrl *string `json:"dbt_cloud_job_run_url,omitempty"` DbtCloudJobRunOutput []dbtCloudJobRunStepWire `json:"dbt_cloud_job_run_output,omitempty"` } @@ -1563,12 +1717,16 @@ func dbtCloudTaskOutputFromWire(w *dbtCloudTaskOutputWire) (*DbtCloudTaskOutput, if w == nil { return nil, nil } + dbtCloudJobRunIdPublicValue, err := int64FromWire(w.DbtCloudJobRunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DbtCloudTaskOutput.DbtCloudJobRunId", err) + } dbtCloudJobRunOutputPublicValue, err := convertSlice(w.DbtCloudJobRunOutput, dbtCloudJobRunStepFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "DbtCloudTaskOutput.DbtCloudJobRunOutput", err) } return &DbtCloudTaskOutput{ - DbtCloudJobRunId: w.DbtCloudJobRunId, + DbtCloudJobRunId: dbtCloudJobRunIdPublicValue, DbtCloudJobRunUrl: w.DbtCloudJobRunUrl, DbtCloudJobRunOutput: dbtCloudJobRunOutputPublicValue, }, nil @@ -1701,28 +1859,36 @@ func dbtTask_DbtTaskOutputFromWire(w *dbtTask_DbtTaskOutputWire) (*DbtTask_DbtTa } type deleteJobRequestWire struct { - JobId *int64 `json:"job_id,omitempty"` + JobId *wireInt64 `json:"job_id,omitempty"` } func deleteJobRequestToWire(v *DeleteJobRequest) (*deleteJobRequestWire, error) { if v == nil { return nil, nil } + jobIdWireValue, err := int64ToWire(v.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DeleteJobRequest.JobId", err) + } return &deleteJobRequestWire{ - JobId: v.JobId, + JobId: jobIdWireValue, }, nil } type deleteRunRequestWire struct { - RunId *int64 `json:"run_id,omitempty"` + RunId *wireInt64 `json:"run_id,omitempty"` } func deleteRunRequestToWire(v *DeleteRunRequest) (*deleteRunRequestWire, error) { if v == nil { return nil, nil } + runIdWireValue, err := int64ToWire(v.RunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DeleteRunRequest.RunId", err) + } return &deleteRunRequestWire{ - RunId: v.RunId, + RunId: runIdWireValue, }, nil } @@ -1843,16 +2009,20 @@ func dockerImageFromWire(w *dockerImageWire) (*DockerImage, error) { } type enforcePolicyComplianceForJobWire struct { - JobId *int64 `json:"job_id,omitempty"` - ValidateOnly *bool `json:"validate_only,omitempty"` + JobId *wireInt64 `json:"job_id,omitempty"` + ValidateOnly *bool `json:"validate_only,omitempty"` } func enforcePolicyComplianceForJobToWire(v *EnforcePolicyComplianceForJob) (*enforcePolicyComplianceForJobWire, error) { if v == nil { return nil, nil } + jobIdWireValue, err := int64ToWire(v.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "EnforcePolicyComplianceForJob.JobId", err) + } return &enforcePolicyComplianceForJobWire{ - JobId: v.JobId, + JobId: jobIdWireValue, ValidateOnly: v.ValidateOnly, }, nil } @@ -1934,7 +2104,7 @@ func environmentFromWire(w *environmentWire) (*Environment, error) { } type exportRunRequestWire struct { - RunId *int64 `json:"run_id,omitempty"` + RunId *wireInt64 `json:"run_id,omitempty"` ViewsToExport ViewsToExport `json:"views_to_export,omitempty"` } @@ -1942,8 +2112,12 @@ func exportRunRequestToWire(v *ExportRunRequest) (*exportRunRequestWire, error) if v == nil { return nil, nil } + runIdWireValue, err := int64ToWire(v.RunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ExportRunRequest.RunId", err) + } return &exportRunRequestWire{ - RunId: v.RunId, + RunId: runIdWireValue, ViewsToExport: v.ViewsToExport, }, nil } @@ -2159,17 +2333,21 @@ func genAiComputeTaskFromWire(w *genAiComputeTaskWire) (*GenAiComputeTask, error } type getJobRequestWire struct { - JobId *int64 `json:"job_id,omitempty"` - IncludeTriggerState *bool `json:"include_trigger_state,omitempty"` - PageToken *string `json:"page_token,omitempty"` + JobId *wireInt64 `json:"job_id,omitempty"` + IncludeTriggerState *bool `json:"include_trigger_state,omitempty"` + PageToken *string `json:"page_token,omitempty"` } func getJobRequestToWire(v *GetJobRequest) (*getJobRequestWire, error) { if v == nil { return nil, nil } + jobIdWireValue, err := int64ToWire(v.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetJobRequest.JobId", err) + } return &getJobRequestWire{ - JobId: v.JobId, + JobId: jobIdWireValue, IncludeTriggerState: v.IncludeTriggerState, PageToken: v.PageToken, }, nil @@ -2177,11 +2355,11 @@ func getJobRequestToWire(v *GetJobRequest) (*getJobRequestWire, error) { type getJobResponseWire struct { NextPageToken *string `json:"next_page_token,omitempty"` - JobId *int64 `json:"job_id,omitempty"` + JobId *wireInt64 `json:"job_id,omitempty"` CreatorUserName *string `json:"creator_user_name,omitempty"` RunAsUserName *string `json:"run_as_user_name,omitempty"` Settings *jobSettingsWire `json:"settings,omitempty"` - CreatedTime *int64 `json:"created_time,omitempty"` + CreatedTime *wireInt64 `json:"created_time,omitempty"` TriggerState *triggerStateWire `json:"trigger_state,omitempty"` HasMore *bool `json:"has_more,omitempty"` EffectiveBudgetPolicyId *string `json:"effective_budget_policy_id,omitempty"` @@ -2193,10 +2371,18 @@ func getJobResponseFromWire(w *getJobResponseWire) (*GetJobResponse, error) { if w == nil { return nil, nil } + jobIdPublicValue, err := int64FromWire(w.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetJobResponse.JobId", err) + } settingsPublicValue, err := jobSettingsFromWire(w.Settings) if err != nil { return nil, fmt.Errorf("%s: %w", "GetJobResponse.Settings", err) } + createdTimePublicValue, err := int64FromWire(w.CreatedTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetJobResponse.CreatedTime", err) + } triggerStatePublicValue, err := triggerStateFromWire(w.TriggerState) if err != nil { return nil, fmt.Errorf("%s: %w", "GetJobResponse.TriggerState", err) @@ -2207,11 +2393,11 @@ func getJobResponseFromWire(w *getJobResponseWire) (*GetJobResponse, error) { } return &GetJobResponse{ NextPageToken: w.NextPageToken, - JobId: w.JobId, + JobId: jobIdPublicValue, CreatorUserName: w.CreatorUserName, RunAsUserName: w.RunAsUserName, Settings: settingsPublicValue, - CreatedTime: w.CreatedTime, + CreatedTime: createdTimePublicValue, TriggerState: triggerStatePublicValue, HasMore: w.HasMore, EffectiveBudgetPolicyId: w.EffectiveBudgetPolicyId, @@ -2221,15 +2407,19 @@ func getJobResponseFromWire(w *getJobResponseWire) (*GetJobResponse, error) { } type getPolicyComplianceForJobRequestWire struct { - JobId *int64 `json:"job_id,omitempty"` + JobId *wireInt64 `json:"job_id,omitempty"` } func getPolicyComplianceForJobRequestToWire(v *GetPolicyComplianceForJobRequest) (*getPolicyComplianceForJobRequestWire, error) { if v == nil { return nil, nil } + jobIdWireValue, err := int64ToWire(v.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetPolicyComplianceForJobRequest.JobId", err) + } return &getPolicyComplianceForJobRequestWire{ - JobId: v.JobId, + JobId: jobIdWireValue, }, nil } @@ -2249,15 +2439,19 @@ func getPolicyComplianceForJobResponseFromWire(w *getPolicyComplianceForJobRespo } type getRunOutputRequestWire struct { - RunId *int64 `json:"run_id,omitempty"` + RunId *wireInt64 `json:"run_id,omitempty"` } func getRunOutputRequestToWire(v *GetRunOutputRequest) (*getRunOutputRequestWire, error) { if v == nil { return nil, nil } + runIdWireValue, err := int64ToWire(v.RunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetRunOutputRequest.RunId", err) + } return &getRunOutputRequestWire{ - RunId: v.RunId, + RunId: runIdWireValue, }, nil } @@ -2397,18 +2591,22 @@ func getRunOutputResponseFromWire(w *getRunOutputResponseWire) (*GetRunOutputRes } type getRunRequestWire struct { - RunId *int64 `json:"run_id,omitempty"` - IncludeHistory *bool `json:"include_history,omitempty"` - IncludeResolvedValues *bool `json:"include_resolved_values,omitempty"` - PageToken *string `json:"page_token,omitempty"` + RunId *wireInt64 `json:"run_id,omitempty"` + IncludeHistory *bool `json:"include_history,omitempty"` + IncludeResolvedValues *bool `json:"include_resolved_values,omitempty"` + PageToken *string `json:"page_token,omitempty"` } func getRunRequestToWire(v *GetRunRequest) (*getRunRequestWire, error) { if v == nil { return nil, nil } + runIdWireValue, err := int64ToWire(v.RunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetRunRequest.RunId", err) + } return &getRunRequestWire{ - RunId: v.RunId, + RunId: runIdWireValue, IncludeHistory: v.IncludeHistory, IncludeResolvedValues: v.IncludeResolvedValues, PageToken: v.PageToken, @@ -2417,11 +2615,11 @@ func getRunRequestToWire(v *GetRunRequest) (*getRunRequestWire, error) { type getRunResponseWire struct { NextPageToken *string `json:"next_page_token,omitempty"` - JobId *int64 `json:"job_id,omitempty"` - RunId *int64 `json:"run_id,omitempty"` + JobId *wireInt64 `json:"job_id,omitempty"` + RunId *wireInt64 `json:"run_id,omitempty"` CreatorUserName *string `json:"creator_user_name,omitempty"` - NumberInJob *int64 `json:"number_in_job,omitempty"` - OriginalAttemptRunId *int64 `json:"original_attempt_run_id,omitempty"` + NumberInJob *wireInt64 `json:"number_in_job,omitempty"` + OriginalAttemptRunId *wireInt64 `json:"original_attempt_run_id,omitempty"` State *runStateWire `json:"state,omitempty"` Schedule *cronScheduleWire `json:"schedule,omitempty"` ClusterSpec *clusterSpecWire `json:"cluster_spec,omitempty"` @@ -2440,25 +2638,41 @@ type getRunResponseWire struct { GitSource *gitSourceWire `json:"git_source,omitempty"` RepairHistory []repairWire `json:"repair_history,omitempty"` Status *runStatusWire `json:"status,omitempty"` - JobRunId *int64 `json:"job_run_id,omitempty"` + JobRunId *wireInt64 `json:"job_run_id,omitempty"` HasMore *bool `json:"has_more,omitempty"` EffectivePerformanceTarget PerformanceTarget_PerformanceTarget `json:"effective_performance_target,omitempty"` EffectiveUsagePolicyId *string `json:"effective_usage_policy_id,omitempty"` DeploymentId *string `json:"deployment_id,omitempty"` VersionId *string `json:"version_id,omitempty"` - StartTime *int64 `json:"start_time,omitempty"` - SetupDuration *int64 `json:"setup_duration,omitempty"` - ExecutionDuration *int64 `json:"execution_duration,omitempty"` - CleanupDuration *int64 `json:"cleanup_duration,omitempty"` - EndTime *int64 `json:"end_time,omitempty"` - RunDuration *int64 `json:"run_duration,omitempty"` - QueueDuration *int64 `json:"queue_duration,omitempty"` + StartTime *wireInt64 `json:"start_time,omitempty"` + SetupDuration *wireInt64 `json:"setup_duration,omitempty"` + ExecutionDuration *wireInt64 `json:"execution_duration,omitempty"` + CleanupDuration *wireInt64 `json:"cleanup_duration,omitempty"` + EndTime *wireInt64 `json:"end_time,omitempty"` + RunDuration *wireInt64 `json:"run_duration,omitempty"` + QueueDuration *wireInt64 `json:"queue_duration,omitempty"` } func getRunResponseFromWire(w *getRunResponseWire) (*GetRunResponse, error) { if w == nil { return nil, nil } + jobIdPublicValue, err := int64FromWire(w.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetRunResponse.JobId", err) + } + runIdPublicValue, err := int64FromWire(w.RunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetRunResponse.RunId", err) + } + numberInJobPublicValue, err := int64FromWire(w.NumberInJob) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetRunResponse.NumberInJob", err) + } + originalAttemptRunIdPublicValue, err := int64FromWire(w.OriginalAttemptRunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetRunResponse.OriginalAttemptRunId", err) + } statePublicValue, err := runStateFromWire(w.State) if err != nil { return nil, fmt.Errorf("%s: %w", "GetRunResponse.State", err) @@ -2507,13 +2721,45 @@ func getRunResponseFromWire(w *getRunResponseWire) (*GetRunResponse, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "GetRunResponse.Status", err) } + jobRunIdPublicValue, err := int64FromWire(w.JobRunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetRunResponse.JobRunId", err) + } + startTimePublicValue, err := int64FromWire(w.StartTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetRunResponse.StartTime", err) + } + setupDurationPublicValue, err := int64FromWire(w.SetupDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetRunResponse.SetupDuration", err) + } + executionDurationPublicValue, err := int64FromWire(w.ExecutionDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetRunResponse.ExecutionDuration", err) + } + cleanupDurationPublicValue, err := int64FromWire(w.CleanupDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetRunResponse.CleanupDuration", err) + } + endTimePublicValue, err := int64FromWire(w.EndTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetRunResponse.EndTime", err) + } + runDurationPublicValue, err := int64FromWire(w.RunDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetRunResponse.RunDuration", err) + } + queueDurationPublicValue, err := int64FromWire(w.QueueDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetRunResponse.QueueDuration", err) + } return &GetRunResponse{ NextPageToken: w.NextPageToken, - JobId: w.JobId, - RunId: w.RunId, + JobId: jobIdPublicValue, + RunId: runIdPublicValue, CreatorUserName: w.CreatorUserName, - NumberInJob: w.NumberInJob, - OriginalAttemptRunId: w.OriginalAttemptRunId, + NumberInJob: numberInJobPublicValue, + OriginalAttemptRunId: originalAttemptRunIdPublicValue, State: statePublicValue, Schedule: schedulePublicValue, ClusterSpec: clusterSpecPublicValue, @@ -2532,19 +2778,19 @@ func getRunResponseFromWire(w *getRunResponseWire) (*GetRunResponse, error) { GitSource: gitSourcePublicValue, RepairHistory: repairHistoryPublicValue, Status: statusPublicValue, - JobRunId: w.JobRunId, + JobRunId: jobRunIdPublicValue, HasMore: w.HasMore, EffectivePerformanceTarget: w.EffectivePerformanceTarget, EffectiveUsagePolicyId: w.EffectiveUsagePolicyId, DeploymentId: w.DeploymentId, VersionId: w.VersionId, - StartTime: w.StartTime, - SetupDuration: w.SetupDuration, - ExecutionDuration: w.ExecutionDuration, - CleanupDuration: w.CleanupDuration, - EndTime: w.EndTime, - RunDuration: w.RunDuration, - QueueDuration: w.QueueDuration, + StartTime: startTimePublicValue, + SetupDuration: setupDurationPublicValue, + ExecutionDuration: executionDurationPublicValue, + CleanupDuration: cleanupDurationPublicValue, + EndTime: endTimePublicValue, + RunDuration: runDurationPublicValue, + QueueDuration: queueDurationPublicValue, }, nil } @@ -3372,17 +3618,21 @@ func jobSourceFromWire(w *jobSourceWire) (*JobSource, error) { type jobsHealthRuleWire struct { Metric JobsHealthMetric `json:"metric,omitempty"` Op JobsHealthOperator `json:"op,omitempty"` - Value *int64 `json:"value,omitempty"` + Value *wireInt64 `json:"value,omitempty"` } func jobsHealthRuleToWire(v *JobsHealthRule) (*jobsHealthRuleWire, error) { if v == nil { return nil, nil } + valueWireValue, err := int64ToWire(v.Value) + if err != nil { + return nil, fmt.Errorf("%s: %w", "JobsHealthRule.Value", err) + } return &jobsHealthRuleWire{ Metric: v.Metric, Op: v.Op, - Value: v.Value, + Value: valueWireValue, }, nil } @@ -3390,10 +3640,14 @@ func jobsHealthRuleFromWire(w *jobsHealthRuleWire) (*JobsHealthRule, error) { if w == nil { return nil, nil } + valuePublicValue, err := int64FromWire(w.Value) + if err != nil { + return nil, fmt.Errorf("%s: %w", "JobsHealthRule.Value", err) + } return &JobsHealthRule{ Metric: w.Metric, Op: w.Op, - Value: w.Value, + Value: valuePublicValue, }, nil } @@ -3585,7 +3839,7 @@ func listJobComplianceForPolicyToWire(v *ListJobComplianceForPolicy) (*listJobCo } type listJobComplianceForPolicy_JobComplianceWire struct { - JobId *int64 `json:"job_id,omitempty"` + JobId *wireInt64 `json:"job_id,omitempty"` IsCompliant *bool `json:"is_compliant,omitempty"` Violations map[string]string `json:"violations,omitempty"` } @@ -3594,8 +3848,12 @@ func listJobComplianceForPolicy_JobComplianceFromWire(w *listJobComplianceForPol if w == nil { return nil, nil } + jobIdPublicValue, err := int64FromWire(w.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListJobComplianceForPolicy_JobCompliance.JobId", err) + } return &ListJobComplianceForPolicy_JobCompliance{ - JobId: w.JobId, + JobId: jobIdPublicValue, IsCompliant: w.IsCompliant, Violations: w.Violations, }, nil @@ -3667,22 +3925,34 @@ func listJobsResponseFromWire(w *listJobsResponseWire) (*ListJobsResponse, error } type listRunsRequestWire struct { - JobId *int64 `json:"job_id,omitempty"` - ActiveOnly *bool `json:"active_only,omitempty"` - CompletedOnly *bool `json:"completed_only,omitempty"` - Offset *int `json:"offset,omitempty"` - Limit *int `json:"limit,omitempty"` - RunType RunType `json:"run_type,omitempty"` - ExpandTasks *bool `json:"expand_tasks,omitempty"` - StartTimeFrom *int64 `json:"start_time_from,omitempty"` - StartTimeTo *int64 `json:"start_time_to,omitempty"` - PageToken *string `json:"page_token,omitempty"` + JobId *wireInt64 `json:"job_id,omitempty"` + ActiveOnly *bool `json:"active_only,omitempty"` + CompletedOnly *bool `json:"completed_only,omitempty"` + Offset *int `json:"offset,omitempty"` + Limit *int `json:"limit,omitempty"` + RunType RunType `json:"run_type,omitempty"` + ExpandTasks *bool `json:"expand_tasks,omitempty"` + StartTimeFrom *wireInt64 `json:"start_time_from,omitempty"` + StartTimeTo *wireInt64 `json:"start_time_to,omitempty"` + PageToken *string `json:"page_token,omitempty"` } func listRunsRequestToWire(v *ListRunsRequest) (*listRunsRequestWire, error) { if v == nil { return nil, nil } + jobIdWireValue, err := int64ToWire(v.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListRunsRequest.JobId", err) + } + startTimeFromWireValue, err := int64ToWire(v.StartTimeFrom) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListRunsRequest.StartTimeFrom", err) + } + startTimeToWireValue, err := int64ToWire(v.StartTimeTo) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListRunsRequest.StartTimeTo", err) + } var stateConstraintActiveOnlyWire *bool var stateConstraintCompletedOnlyWire *bool switch value := v.StateConstraint.(type) { @@ -3699,15 +3969,15 @@ func listRunsRequestToWire(v *ListRunsRequest) (*listRunsRequestWire, error) { return nil, fmt.Errorf("%s: unsupported oneof implementation %T", "ListRunsRequest.StateConstraint", value) } return &listRunsRequestWire{ - JobId: v.JobId, + JobId: jobIdWireValue, ActiveOnly: stateConstraintActiveOnlyWire, CompletedOnly: stateConstraintCompletedOnlyWire, Offset: v.Offset, Limit: v.Limit, RunType: v.RunType, ExpandTasks: v.ExpandTasks, - StartTimeFrom: v.StartTimeFrom, - StartTimeTo: v.StartTimeTo, + StartTimeFrom: startTimeFromWireValue, + StartTimeTo: startTimeToWireValue, PageToken: v.PageToken, }, nil } @@ -3782,6 +4052,34 @@ func logAnalyticsInfoFromWire(w *logAnalyticsInfoWire) (*LogAnalyticsInfo, error }, nil } +type maintenanceWindowWire struct { + StartHour *int `json:"start_hour,omitempty"` + DayOfWeek DayOfWeek `json:"day_of_week,omitempty"` + TimezoneId *string `json:"timezone_id,omitempty"` +} + +func maintenanceWindowToWire(v *MaintenanceWindow) (*maintenanceWindowWire, error) { + if v == nil { + return nil, nil + } + return &maintenanceWindowWire{ + StartHour: v.StartHour, + DayOfWeek: v.DayOfWeek, + TimezoneId: v.TimezoneId, + }, nil +} + +func maintenanceWindowFromWire(w *maintenanceWindowWire) (*MaintenanceWindow, error) { + if w == nil { + return nil, nil + } + return &MaintenanceWindow{ + StartHour: w.StartHour, + DayOfWeek: w.DayOfWeek, + TimezoneId: w.TimezoneId, + }, nil +} + type mavenLibraryWire struct { Coordinates *string `json:"coordinates,omitempty"` Repo *string `json:"repo,omitempty"` @@ -3856,6 +4154,7 @@ func modelTriggerStateFromWire(w *modelTriggerStateWire) (*ModelTriggerState, er type nodeTypeFlexibilityWire struct { AlternateNodeTypeIds []string `json:"alternate_node_type_ids,omitempty"` + AwsContextId *string `json:"aws_context_id,omitempty"` } func nodeTypeFlexibilityToWire(v *NodeTypeFlexibility) (*nodeTypeFlexibilityWire, error) { @@ -3864,6 +4163,7 @@ func nodeTypeFlexibilityToWire(v *NodeTypeFlexibility) (*nodeTypeFlexibilityWire } return &nodeTypeFlexibilityWire{ AlternateNodeTypeIds: v.AlternateNodeTypeIds, + AwsContextId: v.AwsContextId, }, nil } @@ -3873,6 +4173,7 @@ func nodeTypeFlexibilityFromWire(w *nodeTypeFlexibilityWire) (*NodeTypeFlexibili } return &NodeTypeFlexibility{ AlternateNodeTypeIds: w.AlternateNodeTypeIds, + AwsContextId: w.AwsContextId, }, nil } @@ -3951,19 +4252,23 @@ func notificationSettingsFromWire(w *notificationSettingsWire) (*NotificationSet } type outputSchemaInfoWire struct { - CatalogName *string `json:"catalog_name,omitempty"` - SchemaName *string `json:"schema_name,omitempty"` - ExpirationTime *int64 `json:"expiration_time,omitempty"` + CatalogName *string `json:"catalog_name,omitempty"` + SchemaName *string `json:"schema_name,omitempty"` + ExpirationTime *wireInt64 `json:"expiration_time,omitempty"` } func outputSchemaInfoFromWire(w *outputSchemaInfoWire) (*OutputSchemaInfo, error) { if w == nil { return nil, nil } + expirationTimePublicValue, err := int64FromWire(w.ExpirationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "OutputSchemaInfo.ExpirationTime", err) + } return &OutputSchemaInfo{ CatalogName: w.CatalogName, SchemaName: w.SchemaName, - ExpirationTime: w.ExpirationTime, + ExpirationTime: expirationTimePublicValue, }, nil } @@ -4080,15 +4385,19 @@ func periodicTriggerConfigurationFromWire(w *periodicTriggerConfigurationWire) ( } type periodicTriggerStateWire struct { - NextRunTime *int64 `json:"next_run_time,omitempty"` + NextRunTime *wireInt64 `json:"next_run_time,omitempty"` } func periodicTriggerStateFromWire(w *periodicTriggerStateWire) (*PeriodicTriggerState, error) { if w == nil { return nil, nil } + nextRunTimePublicValue, err := int64FromWire(w.NextRunTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PeriodicTriggerState.NextRunTime", err) + } return &PeriodicTriggerState{ - NextRunTime: w.NextRunTime, + NextRunTime: nextRunTimePublicValue, }, nil } @@ -4459,11 +4768,11 @@ func rCranLibraryFromWire(w *rCranLibraryWire) (*RCranLibrary, error) { type repairWire struct { Type RepairType `json:"type,omitempty"` - StartTime *int64 `json:"start_time,omitempty"` - EndTime *int64 `json:"end_time,omitempty"` + StartTime *wireInt64 `json:"start_time,omitempty"` + EndTime *wireInt64 `json:"end_time,omitempty"` State *runStateWire `json:"state,omitempty"` - Id *int64 `json:"id,omitempty"` - TaskRunIds []int64 `json:"task_run_ids,omitempty"` + Id *wireInt64 `json:"id,omitempty"` + TaskRunIds []wireInt64 `json:"task_run_ids,omitempty"` Status *runStatusWire `json:"status,omitempty"` EffectivePerformanceTarget PerformanceTarget_PerformanceTarget `json:"effective_performance_target,omitempty"` } @@ -4472,29 +4781,45 @@ func repairFromWire(w *repairWire) (*Repair, error) { if w == nil { return nil, nil } + startTimePublicValue, err := int64FromWire(w.StartTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Repair.StartTime", err) + } + endTimePublicValue, err := int64FromWire(w.EndTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Repair.EndTime", err) + } statePublicValue, err := runStateFromWire(w.State) if err != nil { return nil, fmt.Errorf("%s: %w", "Repair.State", err) } + idPublicValue, err := int64FromWire(w.Id) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Repair.Id", err) + } + taskRunIdsPublicValue, err := convertSlice(w.TaskRunIds, int64FromWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Repair.TaskRunIds", err) + } statusPublicValue, err := runStatusFromWire(w.Status) if err != nil { return nil, fmt.Errorf("%s: %w", "Repair.Status", err) } return &Repair{ Type: w.Type, - StartTime: w.StartTime, - EndTime: w.EndTime, + StartTime: startTimePublicValue, + EndTime: endTimePublicValue, State: statePublicValue, - Id: w.Id, - TaskRunIds: w.TaskRunIds, + Id: idPublicValue, + TaskRunIds: taskRunIdsPublicValue, Status: statusPublicValue, EffectivePerformanceTarget: w.EffectivePerformanceTarget, }, nil } type repairRunRequestWire struct { - RunId *int64 `json:"run_id,omitempty"` - LatestRepairId *int64 `json:"latest_repair_id,omitempty"` + RunId *wireInt64 `json:"run_id,omitempty"` + LatestRepairId *wireInt64 `json:"latest_repair_id,omitempty"` RerunTasks []string `json:"rerun_tasks,omitempty"` JobParameters map[string]string `json:"job_parameters,omitempty"` RerunAllFailedTasks *bool `json:"rerun_all_failed_tasks,omitempty"` @@ -4514,13 +4839,21 @@ func repairRunRequestToWire(v *RepairRunRequest) (*repairRunRequestWire, error) if v == nil { return nil, nil } + runIdWireValue, err := int64ToWire(v.RunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RepairRunRequest.RunId", err) + } + latestRepairIdWireValue, err := int64ToWire(v.LatestRepairId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RepairRunRequest.LatestRepairId", err) + } pipelineParamsWireValue, err := pipelineParametersToWire(v.PipelineParams) if err != nil { return nil, fmt.Errorf("%s: %w", "RepairRunRequest.PipelineParams", err) } return &repairRunRequestWire{ - RunId: v.RunId, - LatestRepairId: v.LatestRepairId, + RunId: runIdWireValue, + LatestRepairId: latestRepairIdWireValue, RerunTasks: v.RerunTasks, JobParameters: v.JobParameters, RerunAllFailedTasks: v.RerunAllFailedTasks, @@ -4538,20 +4871,24 @@ func repairRunRequestToWire(v *RepairRunRequest) (*repairRunRequestWire, error) } type repairRunResponseWire struct { - RepairId *int64 `json:"repair_id,omitempty"` + RepairId *wireInt64 `json:"repair_id,omitempty"` } func repairRunResponseFromWire(w *repairRunResponseWire) (*RepairRunResponse, error) { if w == nil { return nil, nil } + repairIdPublicValue, err := int64FromWire(w.RepairId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RepairRunResponse.RepairId", err) + } return &RepairRunResponse{ - RepairId: w.RepairId, + RepairId: repairIdPublicValue, }, nil } type resetJobRequestWire struct { - JobId *int64 `json:"job_id,omitempty"` + JobId *wireInt64 `json:"job_id,omitempty"` NewSettings *jobSettingsWire `json:"new_settings,omitempty"` } @@ -4559,12 +4896,16 @@ func resetJobRequestToWire(v *ResetJobRequest) (*resetJobRequestWire, error) { if v == nil { return nil, nil } + jobIdWireValue, err := int64ToWire(v.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ResetJobRequest.JobId", err) + } newSettingsWireValue, err := jobSettingsToWire(v.NewSettings) if err != nil { return nil, fmt.Errorf("%s: %w", "ResetJobRequest.NewSettings", err) } return &resetJobRequestWire{ - JobId: v.JobId, + JobId: jobIdWireValue, NewSettings: newSettingsWireValue, }, nil } @@ -4862,11 +5203,11 @@ func resolvedValues_SqlTaskResolvedValuesFromWire(w *resolvedValues_SqlTaskResol } type runWire struct { - JobId *int64 `json:"job_id,omitempty"` - RunId *int64 `json:"run_id,omitempty"` + JobId *wireInt64 `json:"job_id,omitempty"` + RunId *wireInt64 `json:"run_id,omitempty"` CreatorUserName *string `json:"creator_user_name,omitempty"` - NumberInJob *int64 `json:"number_in_job,omitempty"` - OriginalAttemptRunId *int64 `json:"original_attempt_run_id,omitempty"` + NumberInJob *wireInt64 `json:"number_in_job,omitempty"` + OriginalAttemptRunId *wireInt64 `json:"original_attempt_run_id,omitempty"` State *runStateWire `json:"state,omitempty"` Schedule *cronScheduleWire `json:"schedule,omitempty"` ClusterSpec *clusterSpecWire `json:"cluster_spec,omitempty"` @@ -4885,25 +5226,41 @@ type runWire struct { GitSource *gitSourceWire `json:"git_source,omitempty"` RepairHistory []repairWire `json:"repair_history,omitempty"` Status *runStatusWire `json:"status,omitempty"` - JobRunId *int64 `json:"job_run_id,omitempty"` + JobRunId *wireInt64 `json:"job_run_id,omitempty"` HasMore *bool `json:"has_more,omitempty"` EffectivePerformanceTarget PerformanceTarget_PerformanceTarget `json:"effective_performance_target,omitempty"` EffectiveUsagePolicyId *string `json:"effective_usage_policy_id,omitempty"` DeploymentId *string `json:"deployment_id,omitempty"` VersionId *string `json:"version_id,omitempty"` - StartTime *int64 `json:"start_time,omitempty"` - SetupDuration *int64 `json:"setup_duration,omitempty"` - ExecutionDuration *int64 `json:"execution_duration,omitempty"` - CleanupDuration *int64 `json:"cleanup_duration,omitempty"` - EndTime *int64 `json:"end_time,omitempty"` - RunDuration *int64 `json:"run_duration,omitempty"` - QueueDuration *int64 `json:"queue_duration,omitempty"` + StartTime *wireInt64 `json:"start_time,omitempty"` + SetupDuration *wireInt64 `json:"setup_duration,omitempty"` + ExecutionDuration *wireInt64 `json:"execution_duration,omitempty"` + CleanupDuration *wireInt64 `json:"cleanup_duration,omitempty"` + EndTime *wireInt64 `json:"end_time,omitempty"` + RunDuration *wireInt64 `json:"run_duration,omitempty"` + QueueDuration *wireInt64 `json:"queue_duration,omitempty"` } func runFromWire(w *runWire) (*Run, error) { if w == nil { return nil, nil } + jobIdPublicValue, err := int64FromWire(w.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Run.JobId", err) + } + runIdPublicValue, err := int64FromWire(w.RunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Run.RunId", err) + } + numberInJobPublicValue, err := int64FromWire(w.NumberInJob) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Run.NumberInJob", err) + } + originalAttemptRunIdPublicValue, err := int64FromWire(w.OriginalAttemptRunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Run.OriginalAttemptRunId", err) + } statePublicValue, err := runStateFromWire(w.State) if err != nil { return nil, fmt.Errorf("%s: %w", "Run.State", err) @@ -4952,12 +5309,44 @@ func runFromWire(w *runWire) (*Run, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "Run.Status", err) } + jobRunIdPublicValue, err := int64FromWire(w.JobRunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Run.JobRunId", err) + } + startTimePublicValue, err := int64FromWire(w.StartTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Run.StartTime", err) + } + setupDurationPublicValue, err := int64FromWire(w.SetupDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Run.SetupDuration", err) + } + executionDurationPublicValue, err := int64FromWire(w.ExecutionDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Run.ExecutionDuration", err) + } + cleanupDurationPublicValue, err := int64FromWire(w.CleanupDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Run.CleanupDuration", err) + } + endTimePublicValue, err := int64FromWire(w.EndTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Run.EndTime", err) + } + runDurationPublicValue, err := int64FromWire(w.RunDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Run.RunDuration", err) + } + queueDurationPublicValue, err := int64FromWire(w.QueueDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Run.QueueDuration", err) + } return &Run{ - JobId: w.JobId, - RunId: w.RunId, + JobId: jobIdPublicValue, + RunId: runIdPublicValue, CreatorUserName: w.CreatorUserName, - NumberInJob: w.NumberInJob, - OriginalAttemptRunId: w.OriginalAttemptRunId, + NumberInJob: numberInJobPublicValue, + OriginalAttemptRunId: originalAttemptRunIdPublicValue, State: statePublicValue, Schedule: schedulePublicValue, ClusterSpec: clusterSpecPublicValue, @@ -4976,19 +5365,19 @@ func runFromWire(w *runWire) (*Run, error) { GitSource: gitSourcePublicValue, RepairHistory: repairHistoryPublicValue, Status: statusPublicValue, - JobRunId: w.JobRunId, + JobRunId: jobRunIdPublicValue, HasMore: w.HasMore, EffectivePerformanceTarget: w.EffectivePerformanceTarget, EffectiveUsagePolicyId: w.EffectiveUsagePolicyId, DeploymentId: w.DeploymentId, VersionId: w.VersionId, - StartTime: w.StartTime, - SetupDuration: w.SetupDuration, - ExecutionDuration: w.ExecutionDuration, - CleanupDuration: w.CleanupDuration, - EndTime: w.EndTime, - RunDuration: w.RunDuration, - QueueDuration: w.QueueDuration, + StartTime: startTimePublicValue, + SetupDuration: setupDurationPublicValue, + ExecutionDuration: executionDurationPublicValue, + CleanupDuration: cleanupDurationPublicValue, + EndTime: endTimePublicValue, + RunDuration: runDurationPublicValue, + QueueDuration: queueDurationPublicValue, }, nil } @@ -5010,7 +5399,7 @@ func run_JobLevelParametersFromWire(w *run_JobLevelParametersWire) (*Run_JobLeve } type runJobTaskWire struct { - JobId *int64 `json:"job_id,omitempty"` + JobId *wireInt64 `json:"job_id,omitempty"` JobParameters map[string]string `json:"job_parameters,omitempty"` PipelineParams *pipelineParametersWire `json:"pipeline_params,omitempty"` JarParams []string `json:"jar_params,omitempty"` @@ -5026,12 +5415,16 @@ func runJobTaskToWire(v *RunJobTask) (*runJobTaskWire, error) { if v == nil { return nil, nil } + jobIdWireValue, err := int64ToWire(v.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RunJobTask.JobId", err) + } pipelineParamsWireValue, err := pipelineParametersToWire(v.PipelineParams) if err != nil { return nil, fmt.Errorf("%s: %w", "RunJobTask.PipelineParams", err) } return &runJobTaskWire{ - JobId: v.JobId, + JobId: jobIdWireValue, JobParameters: v.JobParameters, PipelineParams: pipelineParamsWireValue, JarParams: v.JarParams, @@ -5048,12 +5441,16 @@ func runJobTaskFromWire(w *runJobTaskWire) (*RunJobTask, error) { if w == nil { return nil, nil } + jobIdPublicValue, err := int64FromWire(w.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RunJobTask.JobId", err) + } pipelineParamsPublicValue, err := pipelineParametersFromWire(w.PipelineParams) if err != nil { return nil, fmt.Errorf("%s: %w", "RunJobTask.PipelineParams", err) } return &RunJobTask{ - JobId: w.JobId, + JobId: jobIdPublicValue, JobParameters: w.JobParameters, PipelineParams: pipelineParamsPublicValue, JarParams: w.JarParams, @@ -5067,20 +5464,24 @@ func runJobTaskFromWire(w *runJobTaskWire) (*RunJobTask, error) { } type runJobTask_RunJobTaskOutputWire struct { - RunId *int64 `json:"run_id,omitempty"` + RunId *wireInt64 `json:"run_id,omitempty"` } func runJobTask_RunJobTaskOutputFromWire(w *runJobTask_RunJobTaskOutputWire) (*RunJobTask_RunJobTaskOutput, error) { if w == nil { return nil, nil } + runIdPublicValue, err := int64FromWire(w.RunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RunJobTask_RunJobTaskOutput.RunId", err) + } return &RunJobTask_RunJobTaskOutput{ - RunId: w.RunId, + RunId: runIdPublicValue, }, nil } type runNowRequestWire struct { - JobId *int64 `json:"job_id,omitempty"` + JobId *wireInt64 `json:"job_id,omitempty"` JobParameters map[string]string `json:"job_parameters,omitempty"` IdempotencyToken *string `json:"idempotency_token,omitempty"` Queue *queueSettingsWire `json:"queue,omitempty"` @@ -5100,6 +5501,10 @@ func runNowRequestToWire(v *RunNowRequest) (*runNowRequestWire, error) { if v == nil { return nil, nil } + jobIdWireValue, err := int64ToWire(v.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RunNowRequest.JobId", err) + } queueWireValue, err := queueSettingsToWire(v.Queue) if err != nil { return nil, fmt.Errorf("%s: %w", "RunNowRequest.Queue", err) @@ -5109,7 +5514,7 @@ func runNowRequestToWire(v *RunNowRequest) (*runNowRequestWire, error) { return nil, fmt.Errorf("%s: %w", "RunNowRequest.PipelineParams", err) } return &runNowRequestWire{ - JobId: v.JobId, + JobId: jobIdWireValue, JobParameters: v.JobParameters, IdempotencyToken: v.IdempotencyToken, Queue: queueWireValue, @@ -5127,17 +5532,25 @@ func runNowRequestToWire(v *RunNowRequest) (*runNowRequestWire, error) { } type runNowResponseWire struct { - RunId *int64 `json:"run_id,omitempty"` - NumberInJob *int64 `json:"number_in_job,omitempty"` + RunId *wireInt64 `json:"run_id,omitempty"` + NumberInJob *wireInt64 `json:"number_in_job,omitempty"` } func runNowResponseFromWire(w *runNowResponseWire) (*RunNowResponse, error) { if w == nil { return nil, nil } + runIdPublicValue, err := int64FromWire(w.RunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RunNowResponse.RunId", err) + } + numberInJobPublicValue, err := int64FromWire(w.NumberInJob) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RunNowResponse.NumberInJob", err) + } return &RunNowResponse{ - RunId: w.RunId, - NumberInJob: w.NumberInJob, + RunId: runIdPublicValue, + NumberInJob: numberInJobPublicValue, }, nil } @@ -5219,7 +5632,7 @@ func runStatusFromWire(w *runStatusWire) (*RunStatus, error) { } type runTaskWire struct { - RunId *int64 `json:"run_id,omitempty"` + RunId *wireInt64 `json:"run_id,omitempty"` State *runStateWire `json:"state,omitempty"` RunPageUrl *string `json:"run_page_url,omitempty"` ClusterInstance *clusterInstanceWire `json:"cluster_instance,omitempty"` @@ -5269,13 +5682,13 @@ type runTaskWire struct { MinRetryIntervalMillis *int `json:"min_retry_interval_millis,omitempty"` RetryOnTimeout *bool `json:"retry_on_timeout,omitempty"` DisableAutoOptimization *bool `json:"disable_auto_optimization,omitempty"` - StartTime *int64 `json:"start_time,omitempty"` - SetupDuration *int64 `json:"setup_duration,omitempty"` - ExecutionDuration *int64 `json:"execution_duration,omitempty"` - CleanupDuration *int64 `json:"cleanup_duration,omitempty"` - EndTime *int64 `json:"end_time,omitempty"` - RunDuration *int64 `json:"run_duration,omitempty"` - QueueDuration *int64 `json:"queue_duration,omitempty"` + StartTime *wireInt64 `json:"start_time,omitempty"` + SetupDuration *wireInt64 `json:"setup_duration,omitempty"` + ExecutionDuration *wireInt64 `json:"execution_duration,omitempty"` + CleanupDuration *wireInt64 `json:"cleanup_duration,omitempty"` + EndTime *wireInt64 `json:"end_time,omitempty"` + RunDuration *wireInt64 `json:"run_duration,omitempty"` + QueueDuration *wireInt64 `json:"queue_duration,omitempty"` } func runTaskFromWire(w *runTaskWire) (*RunTask, error) { @@ -5366,6 +5779,10 @@ func runTaskFromWire(w *runTaskWire) (*RunTask, error) { if specMembers > 1 { return nil, fmt.Errorf("%s: multiple oneof members set", "RunTask.Spec") } + runIdPublicValue, err := int64FromWire(w.RunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RunTask.RunId", err) + } statePublicValue, err := runStateFromWire(w.State) if err != nil { return nil, fmt.Errorf("%s: %w", "RunTask.State", err) @@ -5414,6 +5831,34 @@ func runTaskFromWire(w *runTaskWire) (*RunTask, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "RunTask.Libraries", err) } + startTimePublicValue, err := int64FromWire(w.StartTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RunTask.StartTime", err) + } + setupDurationPublicValue, err := int64FromWire(w.SetupDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RunTask.SetupDuration", err) + } + executionDurationPublicValue, err := int64FromWire(w.ExecutionDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RunTask.ExecutionDuration", err) + } + cleanupDurationPublicValue, err := int64FromWire(w.CleanupDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RunTask.CleanupDuration", err) + } + endTimePublicValue, err := int64FromWire(w.EndTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RunTask.EndTime", err) + } + runDurationPublicValue, err := int64FromWire(w.RunDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RunTask.RunDuration", err) + } + queueDurationPublicValue, err := int64FromWire(w.QueueDuration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RunTask.QueueDuration", err) + } var environmentRefSelection isRunTask_EnvironmentRef switch { case w.EnvironmentKey != nil: @@ -5556,7 +6001,7 @@ func runTaskFromWire(w *runTaskWire) (*RunTask, error) { specSelection = &RunTask_Spec_JobClusterKey{JobClusterKey: *w.JobClusterKey} } return &RunTask{ - RunId: w.RunId, + RunId: runIdPublicValue, State: statePublicValue, RunPageUrl: w.RunPageUrl, ClusterInstance: clusterInstancePublicValue, @@ -5582,13 +6027,13 @@ func runTaskFromWire(w *runTaskWire) (*RunTask, error) { MinRetryIntervalMillis: w.MinRetryIntervalMillis, RetryOnTimeout: w.RetryOnTimeout, DisableAutoOptimization: w.DisableAutoOptimization, - StartTime: w.StartTime, - SetupDuration: w.SetupDuration, - ExecutionDuration: w.ExecutionDuration, - CleanupDuration: w.CleanupDuration, - EndTime: w.EndTime, - RunDuration: w.RunDuration, - QueueDuration: w.QueueDuration, + StartTime: startTimePublicValue, + SetupDuration: setupDurationPublicValue, + ExecutionDuration: executionDurationPublicValue, + CleanupDuration: cleanupDurationPublicValue, + EndTime: endTimePublicValue, + RunDuration: runDurationPublicValue, + QueueDuration: queueDurationPublicValue, EnvironmentRef: environmentRefSelection, Task: taskSelection, Spec: specSelection, @@ -5935,7 +6380,7 @@ func runTaskSettingsToWire(v *RunTaskSettings) (*runTaskSettingsWire, error) { type runTriggerInfoWire struct { SqlCondition *sqlConditionRunInfoDetailsWire `json:"sql_condition,omitempty"` - RunId *int64 `json:"run_id,omitempty"` + RunId *wireInt64 `json:"run_id,omitempty"` } func runTriggerInfoFromWire(w *runTriggerInfoWire) (*RunTriggerInfo, error) { @@ -5946,9 +6391,13 @@ func runTriggerInfoFromWire(w *runTriggerInfoWire) (*RunTriggerInfo, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "RunTriggerInfo.SqlCondition", err) } + runIdPublicValue, err := int64FromWire(w.RunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RunTriggerInfo.RunId", err) + } return &RunTriggerInfo{ SqlCondition: sqlConditionPublicValue, - RunId: w.RunId, + RunId: runIdPublicValue, }, nil } @@ -6335,8 +6784,8 @@ type sqlTask_SqlDashboardWidgetOutputWire struct { OutputLink *string `json:"output_link,omitempty"` Status SqlTask_SqlTaskQueryStatus `json:"status,omitempty"` Error *sqlTask_SqlOutputErrorWire `json:"error,omitempty"` - StartTime *int64 `json:"start_time,omitempty"` - EndTime *int64 `json:"end_time,omitempty"` + StartTime *wireInt64 `json:"start_time,omitempty"` + EndTime *wireInt64 `json:"end_time,omitempty"` } func sqlTask_SqlDashboardWidgetOutputFromWire(w *sqlTask_SqlDashboardWidgetOutputWire) (*SqlTask_SqlDashboardWidgetOutput, error) { @@ -6347,14 +6796,22 @@ func sqlTask_SqlDashboardWidgetOutputFromWire(w *sqlTask_SqlDashboardWidgetOutpu if err != nil { return nil, fmt.Errorf("%s: %w", "SqlTask_SqlDashboardWidgetOutput.Error", err) } + startTimePublicValue, err := int64FromWire(w.StartTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SqlTask_SqlDashboardWidgetOutput.StartTime", err) + } + endTimePublicValue, err := int64FromWire(w.EndTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SqlTask_SqlDashboardWidgetOutput.EndTime", err) + } return &SqlTask_SqlDashboardWidgetOutput{ WidgetId: w.WidgetId, WidgetTitle: w.WidgetTitle, OutputLink: w.OutputLink, Status: w.Status, Error: errorPublicValue, - StartTime: w.StartTime, - EndTime: w.EndTime, + StartTime: startTimePublicValue, + EndTime: endTimePublicValue, }, nil } @@ -6742,15 +7199,19 @@ func submitRunRequestToWire(v *SubmitRunRequest) (*submitRunRequestWire, error) } type submitRunResponseWire struct { - RunId *int64 `json:"run_id,omitempty"` + RunId *wireInt64 `json:"run_id,omitempty"` } func submitRunResponseFromWire(w *submitRunResponseWire) (*SubmitRunResponse, error) { if w == nil { return nil, nil } + runIdPublicValue, err := int64FromWire(w.RunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SubmitRunResponse.RunId", err) + } return &SubmitRunResponse{ - RunId: w.RunId, + RunId: runIdPublicValue, }, nil } @@ -7694,19 +8155,27 @@ func triggerDetailsFromWire(w *triggerDetailsWire) (*TriggerDetails, error) { } type triggerEvaluationWire struct { - Timestamp *int64 `json:"timestamp,omitempty"` - Description *string `json:"description,omitempty"` - RunId *int64 `json:"run_id,omitempty"` + Timestamp *wireInt64 `json:"timestamp,omitempty"` + Description *string `json:"description,omitempty"` + RunId *wireInt64 `json:"run_id,omitempty"` } func triggerEvaluationFromWire(w *triggerEvaluationWire) (*TriggerEvaluation, error) { if w == nil { return nil, nil } + timestampPublicValue, err := int64FromWire(w.Timestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TriggerEvaluation.Timestamp", err) + } + runIdPublicValue, err := int64FromWire(w.RunId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TriggerEvaluation.RunId", err) + } return &TriggerEvaluation{ - Timestamp: w.Timestamp, + Timestamp: timestampPublicValue, Description: w.Description, - RunId: w.RunId, + RunId: runIdPublicValue, }, nil } @@ -7913,7 +8382,7 @@ func triggerStateFromWire(w *triggerStateWire) (*TriggerState, error) { } type updateJobRequestWire struct { - JobId *int64 `json:"job_id,omitempty"` + JobId *wireInt64 `json:"job_id,omitempty"` NewSettings *jobSettingsWire `json:"new_settings,omitempty"` FieldsToRemove []string `json:"fields_to_remove,omitempty"` } @@ -7922,12 +8391,16 @@ func updateJobRequestToWire(v *UpdateJobRequest) (*updateJobRequestWire, error) if v == nil { return nil, nil } + jobIdWireValue, err := int64ToWire(v.JobId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateJobRequest.JobId", err) + } newSettingsWireValue, err := jobSettingsToWire(v.NewSettings) if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateJobRequest.NewSettings", err) } return &updateJobRequestWire{ - JobId: v.JobId, + JobId: jobIdWireValue, NewSettings: newSettingsWireValue, FieldsToRemove: v.FieldsToRemove, }, nil diff --git a/keyconfigurations/CHANGELOG.md b/keyconfigurations/CHANGELOG.md index 6224c04..19f237c 100644 --- a/keyconfigurations/CHANGELOG.md +++ b/keyconfigurations/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/keyconfigurations/go.mod b/keyconfigurations/go.mod index 45f915a..e7242a6 100644 --- a/keyconfigurations/go.mod +++ b/keyconfigurations/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/keyconfigurations/internal/version.go b/keyconfigurations/internal/version.go index 1b850b8..69444b7 100644 --- a/keyconfigurations/internal/version.go +++ b/keyconfigurations/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-keyconfigurations" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/keyconfigurations/v1/client.go b/keyconfigurations/v1/client.go old mode 100755 new mode 100644 index cd3a4c8..81bdee7 --- a/keyconfigurations/v1/client.go +++ b/keyconfigurations/v1/client.go @@ -102,8 +102,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // // [Authenticate with Google ID tokens]: https://docs.databricks.com/gcp/en/dev-tools/auth/authentication-google-id.html // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateCustomerManagedKeyPublic(ctx context.Context, req *CreateCustomerManagedKeyRequest, opts ...call.Option) (*CustomerManagedKey, error) { - wireReq, err := createCustomerManagedKeyRequestToWire(req) +func (c *internalClient) CreateCustomerManagedKeyPublic(ctx context.Context, req CreateCustomerManagedKeyRequest, opts ...call.Option) (*CustomerManagedKey, error) { + wireReq, err := createCustomerManagedKeyRequestToWire(&req) if err != nil { return nil, err } @@ -175,7 +175,7 @@ func (c *internalClient) CreateCustomerManagedKeyPublic(ctx context.Context, req // Deletes a customer-managed key configuration object for an account. You // cannot delete a configuration that is associated with a running workspace. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteCustomerManagedKeyPublic(ctx context.Context, req *DeleteCustomerManagedKeyRequest, opts ...call.Option) (*CustomerManagedKey, error) { +func (c *internalClient) DeleteCustomerManagedKeyPublic(ctx context.Context, req DeleteCustomerManagedKeyRequest, opts ...call.Option) (*CustomerManagedKey, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -192,7 +192,11 @@ func (c *internalClient) DeleteCustomerManagedKeyPublic(ctx context.Context, req pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/customer-managed-keys/") - pb.singleSegment(*req.CustomerManagedKeyId) + if req.CustomerManagedKeyId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CustomerManagedKeyId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -253,7 +257,7 @@ func (c *internalClient) DeleteCustomerManagedKeyPublic(ctx context.Context, req // This operation is available only if your account is on the E2 version of the // platform.", // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetCustomerManagedKeyPublic(ctx context.Context, req *GetCustomerManagedKeyRequest, opts ...call.Option) (*CustomerManagedKey, error) { +func (c *internalClient) GetCustomerManagedKeyPublic(ctx context.Context, req GetCustomerManagedKeyRequest, opts ...call.Option) (*CustomerManagedKey, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -270,7 +274,11 @@ func (c *internalClient) GetCustomerManagedKeyPublic(ctx context.Context, req *G pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/customer-managed-keys/") - pb.singleSegment(*req.CustomerManagedKeyId) + if req.CustomerManagedKeyId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CustomerManagedKeyId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -317,7 +325,7 @@ func (c *internalClient) GetCustomerManagedKeyPublic(ctx context.Context, req *G // Lists customer-managed key configurations for an account. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListCustomerManagedKeyPublic(ctx context.Context, req *ListCustomerManagedKeyRequest, opts ...call.Option) (*ListCustomerManagedKeyResponse, error) { +func (c *internalClient) ListCustomerManagedKeyPublic(ctx context.Context, req ListCustomerManagedKeyRequest, opts ...call.Option) (*ListCustomerManagedKeyResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") diff --git a/keyconfigurations/v1/genhelper.go b/keyconfigurations/v1/genhelper.go old mode 100755 new mode 100644 index 00010ac..da3c546 --- a/keyconfigurations/v1/genhelper.go +++ b/keyconfigurations/v1/genhelper.go @@ -144,11 +144,12 @@ func executeCall(ctx context.Context, op func(context.Context) error, opts []cal return ops.Execute(ctx, op, opsOpts...) } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -161,13 +162,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/keyconfigurations/v1/wire.go b/keyconfigurations/v1/wire.go old mode 100755 new mode 100644 index d04f117..8b89093 --- a/keyconfigurations/v1/wire.go +++ b/keyconfigurations/v1/wire.go @@ -3,9 +3,55 @@ package keyconfigurations import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type awsKeyInfoWire struct { KeyArn *string `json:"key_arn,omitempty"` KeyAlias *string `json:"key_alias,omitempty"` @@ -174,7 +220,7 @@ func createGcpKeyInfoToWire(v *CreateGcpKeyInfo) (*createGcpKeyInfoWire, error) type customerManagedKeyWire struct { CustomerManagedKeyId *string `json:"customer_managed_key_id,omitempty"` - CreationTime *int64 `json:"creation_time,omitempty"` + CreationTime *wireInt64 `json:"creation_time,omitempty"` AccountId *string `json:"account_id,omitempty"` AwsKeyInfo *awsKeyInfoWire `json:"aws_key_info,omitempty"` AzureKeyInfo *azureKeyInfoWire `json:"azure_key_info,omitempty"` @@ -199,6 +245,10 @@ func customerManagedKeyFromWire(w *customerManagedKeyWire) (*CustomerManagedKey, if keyInfoMembers > 1 { return nil, fmt.Errorf("%s: multiple oneof members set", "CustomerManagedKey.KeyInfo") } + creationTimePublicValue, err := int64FromWire(w.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CustomerManagedKey.CreationTime", err) + } var keyInfoSelection isCustomerManagedKey_KeyInfo switch { case w.AwsKeyInfo != nil: @@ -222,7 +272,7 @@ func customerManagedKeyFromWire(w *customerManagedKeyWire) (*CustomerManagedKey, } return &CustomerManagedKey{ CustomerManagedKeyId: w.CustomerManagedKeyId, - CreationTime: w.CreationTime, + CreationTime: creationTimePublicValue, AccountId: w.AccountId, UseCases: w.UseCases, KeyInfo: keyInfoSelection, diff --git a/knowledgeassistants/CHANGELOG.md b/knowledgeassistants/CHANGELOG.md index 6224c04..19f237c 100644 --- a/knowledgeassistants/CHANGELOG.md +++ b/knowledgeassistants/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/knowledgeassistants/go.mod b/knowledgeassistants/go.mod index 18fc919..d13660f 100644 --- a/knowledgeassistants/go.mod +++ b/knowledgeassistants/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/knowledgeassistants/internal/version.go b/knowledgeassistants/internal/version.go index 609c1b3..01a5e5d 100644 --- a/knowledgeassistants/internal/version.go +++ b/knowledgeassistants/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-knowledgeassistants" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/knowledgeassistants/v1/client.go b/knowledgeassistants/v1/client.go old mode 100755 new mode 100644 index 7484144..cd4c0de --- a/knowledgeassistants/v1/client.go +++ b/knowledgeassistants/v1/client.go @@ -75,8 +75,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Creates an example for a Knowledge Assistant. -func (c *internalClient) CreateExample(ctx context.Context, req *CreateExampleRequest, opts ...call.Option) (*Example, error) { - wireReq, err := createExampleRequestToWire(req) +func (c *internalClient) CreateExample(ctx context.Context, req CreateExampleRequest, opts ...call.Option) (*Example, error) { + wireReq, err := createExampleRequestToWire(&req) if err != nil { return nil, err } @@ -97,7 +97,11 @@ func (c *internalClient) CreateExample(ctx context.Context, req *CreateExampleRe } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/examples") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -145,8 +149,8 @@ func (c *internalClient) CreateExample(ctx context.Context, req *CreateExampleRe } // Creates a Knowledge Assistant. -func (c *internalClient) CreateKnowledgeAssistant(ctx context.Context, req *CreateKnowledgeAssistantRequest, opts ...call.Option) (*KnowledgeAssistant, error) { - wireReq, err := createKnowledgeAssistantRequestToWire(req) +func (c *internalClient) CreateKnowledgeAssistant(ctx context.Context, req CreateKnowledgeAssistantRequest, opts ...call.Option) (*KnowledgeAssistant, error) { + wireReq, err := createKnowledgeAssistantRequestToWire(&req) if err != nil { return nil, err } @@ -211,8 +215,8 @@ func (c *internalClient) CreateKnowledgeAssistant(ctx context.Context, req *Crea } // Creates a Knowledge Source under a Knowledge Assistant. -func (c *internalClient) CreateKnowledgeSource(ctx context.Context, req *CreateKnowledgeSourceRequest, opts ...call.Option) (*KnowledgeSource, error) { - wireReq, err := createKnowledgeSourceRequestToWire(req) +func (c *internalClient) CreateKnowledgeSource(ctx context.Context, req CreateKnowledgeSourceRequest, opts ...call.Option) (*KnowledgeSource, error) { + wireReq, err := createKnowledgeSourceRequestToWire(&req) if err != nil { return nil, err } @@ -233,7 +237,11 @@ func (c *internalClient) CreateKnowledgeSource(ctx context.Context, req *CreateK } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/knowledge-sources") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -281,7 +289,7 @@ func (c *internalClient) CreateKnowledgeSource(ctx context.Context, req *CreateK } // Deletes an example from a Knowledge Assistant. -func (c *internalClient) DeleteExample(ctx context.Context, req *DeleteExampleRequest, opts ...call.Option) error { +func (c *internalClient) DeleteExample(ctx context.Context, req DeleteExampleRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -295,7 +303,11 @@ func (c *internalClient) DeleteExample(ctx context.Context, req *DeleteExampleRe } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -332,7 +344,7 @@ func (c *internalClient) DeleteExample(ctx context.Context, req *DeleteExampleRe } // Deletes a Knowledge Assistant. -func (c *internalClient) DeleteKnowledgeAssistant(ctx context.Context, req *DeleteKnowledgeAssistantRequest, opts ...call.Option) error { +func (c *internalClient) DeleteKnowledgeAssistant(ctx context.Context, req DeleteKnowledgeAssistantRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -346,7 +358,11 @@ func (c *internalClient) DeleteKnowledgeAssistant(ctx context.Context, req *Dele } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -383,7 +399,7 @@ func (c *internalClient) DeleteKnowledgeAssistant(ctx context.Context, req *Dele } // Deletes a Knowledge Source. -func (c *internalClient) DeleteKnowledgeSource(ctx context.Context, req *DeleteKnowledgeSourceRequest, opts ...call.Option) error { +func (c *internalClient) DeleteKnowledgeSource(ctx context.Context, req DeleteKnowledgeSourceRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -397,7 +413,11 @@ func (c *internalClient) DeleteKnowledgeSource(ctx context.Context, req *DeleteK } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -434,7 +454,7 @@ func (c *internalClient) DeleteKnowledgeSource(ctx context.Context, req *DeleteK } // Gets an example from a Knowledge Assistant. -func (c *internalClient) GetExample(ctx context.Context, req *GetExampleRequest, opts ...call.Option) (*Example, error) { +func (c *internalClient) GetExample(ctx context.Context, req GetExampleRequest, opts ...call.Option) (*Example, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -448,7 +468,11 @@ func (c *internalClient) GetExample(ctx context.Context, req *GetExampleRequest, } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -494,7 +518,7 @@ func (c *internalClient) GetExample(ctx context.Context, req *GetExampleRequest, } // Gets a Knowledge Assistant. -func (c *internalClient) GetKnowledgeAssistant(ctx context.Context, req *GetKnowledgeAssistantRequest, opts ...call.Option) (*KnowledgeAssistant, error) { +func (c *internalClient) GetKnowledgeAssistant(ctx context.Context, req GetKnowledgeAssistantRequest, opts ...call.Option) (*KnowledgeAssistant, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -508,7 +532,11 @@ func (c *internalClient) GetKnowledgeAssistant(ctx context.Context, req *GetKnow } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -554,7 +582,7 @@ func (c *internalClient) GetKnowledgeAssistant(ctx context.Context, req *GetKnow } // Gets a Knowledge Source. -func (c *internalClient) GetKnowledgeSource(ctx context.Context, req *GetKnowledgeSourceRequest, opts ...call.Option) (*KnowledgeSource, error) { +func (c *internalClient) GetKnowledgeSource(ctx context.Context, req GetKnowledgeSourceRequest, opts ...call.Option) (*KnowledgeSource, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -568,7 +596,11 @@ func (c *internalClient) GetKnowledgeSource(ctx context.Context, req *GetKnowled } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -614,8 +646,8 @@ func (c *internalClient) GetKnowledgeSource(ctx context.Context, req *GetKnowled } // Lists examples under a Knowledge Assistant. -func (c *internalClient) ListExamples(ctx context.Context, req *ListExamplesRequest, opts ...call.Option) (*ListExamplesResponse, error) { - wireReq, err := listExamplesRequestToWire(req) +func (c *internalClient) ListExamples(ctx context.Context, req ListExamplesRequest, opts ...call.Option) (*ListExamplesResponse, error) { + wireReq, err := listExamplesRequestToWire(&req) if err != nil { return nil, err } @@ -632,7 +664,11 @@ func (c *internalClient) ListExamples(ctx context.Context, req *ListExamplesRequ } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/examples") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -689,7 +725,7 @@ func (c *internalClient) ListExamples(ctx context.Context, req *ListExamplesRequ // // For example: // -// for item, err := range c.ListExamplesIter(ctx, &ListExamplesRequest{}) { +// for item, err := range c.ListExamplesIter(ctx, ListExamplesRequest{}) { // if err != nil { // return err // } @@ -701,16 +737,13 @@ func (c *internalClient) ListExamples(ctx context.Context, req *ListExamplesRequ // // Callers who need custom pagination logic should use // ListExamples directly. -func (c *internalClient) ListExamplesIter(ctx context.Context, req *ListExamplesRequest, opts ...call.Option) iter.Seq2[*Example, error] { +func (c *internalClient) ListExamplesIter(ctx context.Context, req ListExamplesRequest, opts ...call.Option) iter.Seq2[*Example, error] { return func(yield func(*Example, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListExamplesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListExamples(ctx, &pageReq, opts...) + resp, err := c.ListExamples(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -729,8 +762,8 @@ func (c *internalClient) ListExamplesIter(ctx context.Context, req *ListExamples } // List Knowledge Assistants -func (c *internalClient) ListKnowledgeAssistants(ctx context.Context, req *ListKnowledgeAssistantsRequest, opts ...call.Option) (*ListKnowledgeAssistantsResponse, error) { - wireReq, err := listKnowledgeAssistantsRequestToWire(req) +func (c *internalClient) ListKnowledgeAssistants(ctx context.Context, req ListKnowledgeAssistantsRequest, opts ...call.Option) (*ListKnowledgeAssistantsResponse, error) { + wireReq, err := listKnowledgeAssistantsRequestToWire(&req) if err != nil { return nil, err } @@ -800,7 +833,7 @@ func (c *internalClient) ListKnowledgeAssistants(ctx context.Context, req *ListK // // For example: // -// for item, err := range c.ListKnowledgeAssistantsIter(ctx, &ListKnowledgeAssistantsRequest{}) { +// for item, err := range c.ListKnowledgeAssistantsIter(ctx, ListKnowledgeAssistantsRequest{}) { // if err != nil { // return err // } @@ -812,16 +845,13 @@ func (c *internalClient) ListKnowledgeAssistants(ctx context.Context, req *ListK // // Callers who need custom pagination logic should use // ListKnowledgeAssistants directly. -func (c *internalClient) ListKnowledgeAssistantsIter(ctx context.Context, req *ListKnowledgeAssistantsRequest, opts ...call.Option) iter.Seq2[*KnowledgeAssistant, error] { +func (c *internalClient) ListKnowledgeAssistantsIter(ctx context.Context, req ListKnowledgeAssistantsRequest, opts ...call.Option) iter.Seq2[*KnowledgeAssistant, error] { return func(yield func(*KnowledgeAssistant, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListKnowledgeAssistantsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListKnowledgeAssistants(ctx, &pageReq, opts...) + resp, err := c.ListKnowledgeAssistants(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -840,8 +870,8 @@ func (c *internalClient) ListKnowledgeAssistantsIter(ctx context.Context, req *L } // Lists Knowledge Sources under a Knowledge Assistant. -func (c *internalClient) ListKnowledgeSources(ctx context.Context, req *ListKnowledgeSourcesRequest, opts ...call.Option) (*ListKnowledgeSourcesResponse, error) { - wireReq, err := listKnowledgeSourcesRequestToWire(req) +func (c *internalClient) ListKnowledgeSources(ctx context.Context, req ListKnowledgeSourcesRequest, opts ...call.Option) (*ListKnowledgeSourcesResponse, error) { + wireReq, err := listKnowledgeSourcesRequestToWire(&req) if err != nil { return nil, err } @@ -858,7 +888,11 @@ func (c *internalClient) ListKnowledgeSources(ctx context.Context, req *ListKnow } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/knowledge-sources") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -915,7 +949,7 @@ func (c *internalClient) ListKnowledgeSources(ctx context.Context, req *ListKnow // // For example: // -// for item, err := range c.ListKnowledgeSourcesIter(ctx, &ListKnowledgeSourcesRequest{}) { +// for item, err := range c.ListKnowledgeSourcesIter(ctx, ListKnowledgeSourcesRequest{}) { // if err != nil { // return err // } @@ -927,16 +961,13 @@ func (c *internalClient) ListKnowledgeSources(ctx context.Context, req *ListKnow // // Callers who need custom pagination logic should use // ListKnowledgeSources directly. -func (c *internalClient) ListKnowledgeSourcesIter(ctx context.Context, req *ListKnowledgeSourcesRequest, opts ...call.Option) iter.Seq2[*KnowledgeSource, error] { +func (c *internalClient) ListKnowledgeSourcesIter(ctx context.Context, req ListKnowledgeSourcesRequest, opts ...call.Option) iter.Seq2[*KnowledgeSource, error] { return func(yield func(*KnowledgeSource, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListKnowledgeSourcesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListKnowledgeSources(ctx, &pageReq, opts...) + resp, err := c.ListKnowledgeSources(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -956,8 +987,8 @@ func (c *internalClient) ListKnowledgeSourcesIter(ctx context.Context, req *List // Sync all non-index Knowledge Sources for a Knowledge Assistant (index sources // do not require sync) -func (c *internalClient) SyncKnowledgeSources(ctx context.Context, req *SyncKnowledgeSourcesRequest, opts ...call.Option) error { - wireReq, err := syncKnowledgeSourcesRequestToWire(req) +func (c *internalClient) SyncKnowledgeSources(ctx context.Context, req SyncKnowledgeSourcesRequest, opts ...call.Option) error { + wireReq, err := syncKnowledgeSourcesRequestToWire(&req) if err != nil { return err } @@ -978,7 +1009,11 @@ func (c *internalClient) SyncKnowledgeSources(ctx context.Context, req *SyncKnow } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/knowledge-sources:sync") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1017,8 +1052,8 @@ func (c *internalClient) SyncKnowledgeSources(ctx context.Context, req *SyncKnow } // Updates an example in a Knowledge Assistant. -func (c *internalClient) UpdateExample(ctx context.Context, req *UpdateExampleRequest, opts ...call.Option) (*Example, error) { - wireReq, err := updateExampleRequestToWire(req) +func (c *internalClient) UpdateExample(ctx context.Context, req UpdateExampleRequest, opts ...call.Option) (*Example, error) { + wireReq, err := updateExampleRequestToWire(&req) if err != nil { return nil, err } @@ -1039,7 +1074,11 @@ func (c *internalClient) UpdateExample(ctx context.Context, req *UpdateExampleRe } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -1089,8 +1128,8 @@ func (c *internalClient) UpdateExample(ctx context.Context, req *UpdateExampleRe } // Updates a Knowledge Assistant. -func (c *internalClient) UpdateKnowledgeAssistant(ctx context.Context, req *UpdateKnowledgeAssistantRequest, opts ...call.Option) (*KnowledgeAssistant, error) { - wireReq, err := updateKnowledgeAssistantRequestToWire(req) +func (c *internalClient) UpdateKnowledgeAssistant(ctx context.Context, req UpdateKnowledgeAssistantRequest, opts ...call.Option) (*KnowledgeAssistant, error) { + wireReq, err := updateKnowledgeAssistantRequestToWire(&req) if err != nil { return nil, err } @@ -1111,7 +1150,11 @@ func (c *internalClient) UpdateKnowledgeAssistant(ctx context.Context, req *Upda } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.KnowledgeAssistant.Name) + if req.KnowledgeAssistant == nil || req.KnowledgeAssistant.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.KnowledgeAssistant.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -1161,8 +1204,8 @@ func (c *internalClient) UpdateKnowledgeAssistant(ctx context.Context, req *Upda } // Updates a Knowledge Source. -func (c *internalClient) UpdateKnowledgeSource(ctx context.Context, req *UpdateKnowledgeSourceRequest, opts ...call.Option) (*KnowledgeSource, error) { - wireReq, err := updateKnowledgeSourceRequestToWire(req) +func (c *internalClient) UpdateKnowledgeSource(ctx context.Context, req UpdateKnowledgeSourceRequest, opts ...call.Option) (*KnowledgeSource, error) { + wireReq, err := updateKnowledgeSourceRequestToWire(&req) if err != nil { return nil, err } @@ -1183,7 +1226,11 @@ func (c *internalClient) UpdateKnowledgeSource(ctx context.Context, req *UpdateK } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { diff --git a/knowledgeassistants/v1/genhelper.go b/knowledgeassistants/v1/genhelper.go old mode 100755 new mode 100644 index 70db819..0ae65a5 --- a/knowledgeassistants/v1/genhelper.go +++ b/knowledgeassistants/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/lakeview/CHANGELOG.md b/lakeview/CHANGELOG.md index 6224c04..19f237c 100644 --- a/lakeview/CHANGELOG.md +++ b/lakeview/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/lakeview/go.mod b/lakeview/go.mod index 3ef74fe..252b809 100644 --- a/lakeview/go.mod +++ b/lakeview/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/lakeview/internal/version.go b/lakeview/internal/version.go index cc4cd89..96202ae 100644 --- a/lakeview/internal/version.go +++ b/lakeview/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-lakeview" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/lakeview/v1/client.go b/lakeview/v1/client.go old mode 100755 new mode 100644 index d63f81e..7b75e12 --- a/lakeview/v1/client.go +++ b/lakeview/v1/client.go @@ -75,8 +75,10 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Create a draft dashboard. -func (c *internalClient) CreateDashboard(ctx context.Context, req *CreateDashboardRequest, opts ...call.Option) (*Dashboard, error) { - wireReq, err := createDashboardRequestToWire(req) +// +// Requires the Databricks SQL access entitlement. +func (c *internalClient) CreateDashboard(ctx context.Context, req CreateDashboardRequest, opts ...call.Option) (*Dashboard, error) { + wireReq, err := createDashboardRequestToWire(&req) if err != nil { return nil, err } @@ -147,8 +149,8 @@ func (c *internalClient) CreateDashboard(ctx context.Context, req *CreateDashboa } // Create dashboard schedule. -func (c *internalClient) CreateSchedule(ctx context.Context, req *CreateScheduleRequest, opts ...call.Option) (*Schedule, error) { - wireReq, err := createScheduleRequestToWire(req) +func (c *internalClient) CreateSchedule(ctx context.Context, req CreateScheduleRequest, opts ...call.Option) (*Schedule, error) { + wireReq, err := createScheduleRequestToWire(&req) if err != nil { return nil, err } @@ -169,7 +171,11 @@ func (c *internalClient) CreateSchedule(ctx context.Context, req *CreateSchedule } pb := pathBuilder{} pb.literal("/api/2.0/lakeview/dashboards/") - pb.singleSegment(*req.Schedule.DashboardId) + if req.Schedule == nil || req.Schedule.DashboardId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Schedule.DashboardId) + } pb.literal("/schedules") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -217,8 +223,8 @@ func (c *internalClient) CreateSchedule(ctx context.Context, req *CreateSchedule } // Create schedule subscription. -func (c *internalClient) CreateSubscription(ctx context.Context, req *CreateSubscriptionRequest, opts ...call.Option) (*Subscription, error) { - wireReq, err := createSubscriptionRequestToWire(req) +func (c *internalClient) CreateSubscription(ctx context.Context, req CreateSubscriptionRequest, opts ...call.Option) (*Subscription, error) { + wireReq, err := createSubscriptionRequestToWire(&req) if err != nil { return nil, err } @@ -239,9 +245,17 @@ func (c *internalClient) CreateSubscription(ctx context.Context, req *CreateSubs } pb := pathBuilder{} pb.literal("/api/2.0/lakeview/dashboards/") - pb.singleSegment(*req.Subscription.DashboardId) + if req.Subscription == nil || req.Subscription.DashboardId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Subscription.DashboardId) + } pb.literal("/schedules/") - pb.singleSegment(*req.Subscription.ScheduleId) + if req.Subscription == nil || req.Subscription.ScheduleId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Subscription.ScheduleId) + } pb.literal("/subscriptions") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -289,8 +303,8 @@ func (c *internalClient) CreateSubscription(ctx context.Context, req *CreateSubs } // Delete dashboard schedule. -func (c *internalClient) DeleteSchedule(ctx context.Context, req *DeleteScheduleRequest, opts ...call.Option) error { - wireReq, err := deleteScheduleRequestToWire(req) +func (c *internalClient) DeleteSchedule(ctx context.Context, req DeleteScheduleRequest, opts ...call.Option) error { + wireReq, err := deleteScheduleRequestToWire(&req) if err != nil { return err } @@ -307,9 +321,17 @@ func (c *internalClient) DeleteSchedule(ctx context.Context, req *DeleteSchedule } pb := pathBuilder{} pb.literal("/api/2.0/lakeview/dashboards/") - pb.singleSegment(*req.DashboardId) + if req.DashboardId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DashboardId) + } pb.literal("/schedules/") - pb.singleSegment(*req.ScheduleId) + if req.ScheduleId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ScheduleId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "etag", wireReq.Etag); err != nil { @@ -349,8 +371,8 @@ func (c *internalClient) DeleteSchedule(ctx context.Context, req *DeleteSchedule } // Delete schedule subscription. -func (c *internalClient) DeleteSubscription(ctx context.Context, req *DeleteSubscriptionRequest, opts ...call.Option) error { - wireReq, err := deleteSubscriptionRequestToWire(req) +func (c *internalClient) DeleteSubscription(ctx context.Context, req DeleteSubscriptionRequest, opts ...call.Option) error { + wireReq, err := deleteSubscriptionRequestToWire(&req) if err != nil { return err } @@ -367,11 +389,23 @@ func (c *internalClient) DeleteSubscription(ctx context.Context, req *DeleteSubs } pb := pathBuilder{} pb.literal("/api/2.0/lakeview/dashboards/") - pb.singleSegment(*req.DashboardId) + if req.DashboardId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DashboardId) + } pb.literal("/schedules/") - pb.singleSegment(*req.ScheduleId) + if req.ScheduleId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ScheduleId) + } pb.literal("/subscriptions/") - pb.singleSegment(*req.SubscriptionId) + if req.SubscriptionId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SubscriptionId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "etag", wireReq.Etag); err != nil { @@ -411,7 +445,9 @@ func (c *internalClient) DeleteSubscription(ctx context.Context, req *DeleteSubs } // Get a draft dashboard. -func (c *internalClient) GetDashboard(ctx context.Context, req *GetDashboardRequest, opts ...call.Option) (*Dashboard, error) { +// +// Requires the Databricks SQL access entitlement. +func (c *internalClient) GetDashboard(ctx context.Context, req GetDashboardRequest, opts ...call.Option) (*Dashboard, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -425,7 +461,11 @@ func (c *internalClient) GetDashboard(ctx context.Context, req *GetDashboardRequ } pb := pathBuilder{} pb.literal("/api/2.0/lakeview/dashboards/") - pb.singleSegment(*req.DashboardId) + if req.DashboardId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DashboardId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -471,7 +511,13 @@ func (c *internalClient) GetDashboard(ctx context.Context, req *GetDashboardRequ } // Get the current published dashboard. -func (c *internalClient) GetPublishedDashboard(ctx context.Context, req *GetPublishedDashboardRequest, opts ...call.Option) (*PublishedDashboard, error) { +// +// The caller must be a workspace user with one of the following entitlements: +// Workspace access, Databricks SQL access, or Consumer access. +// +// Account-level users who are not members of the workspace cannot call this +// endpoint, even if the dashboard has been shared with them. +func (c *internalClient) GetPublishedDashboard(ctx context.Context, req GetPublishedDashboardRequest, opts ...call.Option) (*PublishedDashboard, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -485,7 +531,11 @@ func (c *internalClient) GetPublishedDashboard(ctx context.Context, req *GetPubl } pb := pathBuilder{} pb.literal("/api/2.0/lakeview/dashboards/") - pb.singleSegment(*req.DashboardId) + if req.DashboardId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DashboardId) + } pb.literal("/published") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -533,8 +583,14 @@ func (c *internalClient) GetPublishedDashboard(ctx context.Context, req *GetPubl // Get a required authorization details and scopes of a published dashboard to // mint an OAuth token. -func (c *internalClient) GetPublishedDashboardTokenInfo(ctx context.Context, req *GetPublishedDashboardTokenInfoRequest, opts ...call.Option) (*GetPublishedDashboardTokenInfoResponse, error) { - wireReq, err := getPublishedDashboardTokenInfoRequestToWire(req) +// +// The caller must be a workspace user with one of the following entitlements: +// Workspace access, Databricks SQL access, or Consumer access. +// +// Account-level users who are not members of the workspace cannot call this +// endpoint, even if the dashboard has been shared with them. +func (c *internalClient) GetPublishedDashboardTokenInfo(ctx context.Context, req GetPublishedDashboardTokenInfoRequest, opts ...call.Option) (*GetPublishedDashboardTokenInfoResponse, error) { + wireReq, err := getPublishedDashboardTokenInfoRequestToWire(&req) if err != nil { return nil, err } @@ -551,7 +607,11 @@ func (c *internalClient) GetPublishedDashboardTokenInfo(ctx context.Context, req } pb := pathBuilder{} pb.literal("/api/2.0/lakeview/dashboards/") - pb.singleSegment(*req.DashboardId) + if req.DashboardId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DashboardId) + } pb.literal("/published/tokeninfo") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -604,7 +664,7 @@ func (c *internalClient) GetPublishedDashboardTokenInfo(ctx context.Context, req } // Get dashboard schedule. -func (c *internalClient) GetSchedule(ctx context.Context, req *GetScheduleRequest, opts ...call.Option) (*Schedule, error) { +func (c *internalClient) GetSchedule(ctx context.Context, req GetScheduleRequest, opts ...call.Option) (*Schedule, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -618,9 +678,17 @@ func (c *internalClient) GetSchedule(ctx context.Context, req *GetScheduleReques } pb := pathBuilder{} pb.literal("/api/2.0/lakeview/dashboards/") - pb.singleSegment(*req.DashboardId) + if req.DashboardId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DashboardId) + } pb.literal("/schedules/") - pb.singleSegment(*req.ScheduleId) + if req.ScheduleId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ScheduleId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -666,7 +734,7 @@ func (c *internalClient) GetSchedule(ctx context.Context, req *GetScheduleReques } // Get schedule subscription. -func (c *internalClient) GetSubscription(ctx context.Context, req *GetSubscriptionRequest, opts ...call.Option) (*Subscription, error) { +func (c *internalClient) GetSubscription(ctx context.Context, req GetSubscriptionRequest, opts ...call.Option) (*Subscription, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -680,11 +748,23 @@ func (c *internalClient) GetSubscription(ctx context.Context, req *GetSubscripti } pb := pathBuilder{} pb.literal("/api/2.0/lakeview/dashboards/") - pb.singleSegment(*req.DashboardId) + if req.DashboardId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DashboardId) + } pb.literal("/schedules/") - pb.singleSegment(*req.ScheduleId) + if req.ScheduleId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ScheduleId) + } pb.literal("/subscriptions/") - pb.singleSegment(*req.SubscriptionId) + if req.SubscriptionId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SubscriptionId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -730,8 +810,10 @@ func (c *internalClient) GetSubscription(ctx context.Context, req *GetSubscripti } // List dashboards. -func (c *internalClient) ListDashboards(ctx context.Context, req *ListDashboardsRequest, opts ...call.Option) (*ListDashboardsResponse, error) { - wireReq, err := listDashboardsRequestToWire(req) +// +// Requires the Databricks SQL access entitlement. +func (c *internalClient) ListDashboards(ctx context.Context, req ListDashboardsRequest, opts ...call.Option) (*ListDashboardsResponse, error) { + wireReq, err := listDashboardsRequestToWire(&req) if err != nil { return nil, err } @@ -809,7 +891,7 @@ func (c *internalClient) ListDashboards(ctx context.Context, req *ListDashboards // // For example: // -// for item, err := range c.ListDashboardsIter(ctx, &ListDashboardsRequest{}) { +// for item, err := range c.ListDashboardsIter(ctx, ListDashboardsRequest{}) { // if err != nil { // return err // } @@ -821,16 +903,13 @@ func (c *internalClient) ListDashboards(ctx context.Context, req *ListDashboards // // Callers who need custom pagination logic should use // ListDashboards directly. -func (c *internalClient) ListDashboardsIter(ctx context.Context, req *ListDashboardsRequest, opts ...call.Option) iter.Seq2[*Dashboard, error] { +func (c *internalClient) ListDashboardsIter(ctx context.Context, req ListDashboardsRequest, opts ...call.Option) iter.Seq2[*Dashboard, error] { return func(yield func(*Dashboard, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListDashboardsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListDashboards(ctx, &pageReq, opts...) + resp, err := c.ListDashboards(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -849,8 +928,8 @@ func (c *internalClient) ListDashboardsIter(ctx context.Context, req *ListDashbo } // List dashboard schedules. -func (c *internalClient) ListSchedules(ctx context.Context, req *ListSchedulesRequest, opts ...call.Option) (*ListSchedulesResponse, error) { - wireReq, err := listSchedulesRequestToWire(req) +func (c *internalClient) ListSchedules(ctx context.Context, req ListSchedulesRequest, opts ...call.Option) (*ListSchedulesResponse, error) { + wireReq, err := listSchedulesRequestToWire(&req) if err != nil { return nil, err } @@ -867,7 +946,11 @@ func (c *internalClient) ListSchedules(ctx context.Context, req *ListSchedulesRe } pb := pathBuilder{} pb.literal("/api/2.0/lakeview/dashboards/") - pb.singleSegment(*req.DashboardId) + if req.DashboardId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DashboardId) + } pb.literal("/schedules") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -924,7 +1007,7 @@ func (c *internalClient) ListSchedules(ctx context.Context, req *ListSchedulesRe // // For example: // -// for item, err := range c.ListSchedulesIter(ctx, &ListSchedulesRequest{}) { +// for item, err := range c.ListSchedulesIter(ctx, ListSchedulesRequest{}) { // if err != nil { // return err // } @@ -936,16 +1019,13 @@ func (c *internalClient) ListSchedules(ctx context.Context, req *ListSchedulesRe // // Callers who need custom pagination logic should use // ListSchedules directly. -func (c *internalClient) ListSchedulesIter(ctx context.Context, req *ListSchedulesRequest, opts ...call.Option) iter.Seq2[*Schedule, error] { +func (c *internalClient) ListSchedulesIter(ctx context.Context, req ListSchedulesRequest, opts ...call.Option) iter.Seq2[*Schedule, error] { return func(yield func(*Schedule, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListSchedulesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListSchedules(ctx, &pageReq, opts...) + resp, err := c.ListSchedules(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -964,8 +1044,8 @@ func (c *internalClient) ListSchedulesIter(ctx context.Context, req *ListSchedul } // List schedule subscriptions. -func (c *internalClient) ListSubscriptions(ctx context.Context, req *ListSubscriptionsRequest, opts ...call.Option) (*ListSubscriptionsResponse, error) { - wireReq, err := listSubscriptionsRequestToWire(req) +func (c *internalClient) ListSubscriptions(ctx context.Context, req ListSubscriptionsRequest, opts ...call.Option) (*ListSubscriptionsResponse, error) { + wireReq, err := listSubscriptionsRequestToWire(&req) if err != nil { return nil, err } @@ -982,9 +1062,17 @@ func (c *internalClient) ListSubscriptions(ctx context.Context, req *ListSubscri } pb := pathBuilder{} pb.literal("/api/2.0/lakeview/dashboards/") - pb.singleSegment(*req.DashboardId) + if req.DashboardId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DashboardId) + } pb.literal("/schedules/") - pb.singleSegment(*req.ScheduleId) + if req.ScheduleId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ScheduleId) + } pb.literal("/subscriptions") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1041,7 +1129,7 @@ func (c *internalClient) ListSubscriptions(ctx context.Context, req *ListSubscri // // For example: // -// for item, err := range c.ListSubscriptionsIter(ctx, &ListSubscriptionsRequest{}) { +// for item, err := range c.ListSubscriptionsIter(ctx, ListSubscriptionsRequest{}) { // if err != nil { // return err // } @@ -1053,16 +1141,13 @@ func (c *internalClient) ListSubscriptions(ctx context.Context, req *ListSubscri // // Callers who need custom pagination logic should use // ListSubscriptions directly. -func (c *internalClient) ListSubscriptionsIter(ctx context.Context, req *ListSubscriptionsRequest, opts ...call.Option) iter.Seq2[*Subscription, error] { +func (c *internalClient) ListSubscriptionsIter(ctx context.Context, req ListSubscriptionsRequest, opts ...call.Option) iter.Seq2[*Subscription, error] { return func(yield func(*Subscription, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListSubscriptionsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListSubscriptions(ctx, &pageReq, opts...) + resp, err := c.ListSubscriptions(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1080,9 +1165,10 @@ func (c *internalClient) ListSubscriptionsIter(ctx context.Context, req *ListSub } } -// Migrates a classic SQL dashboard to Lakeview. -func (c *internalClient) MigrateDashboard(ctx context.Context, req *MigrateDashboardRequest, opts ...call.Option) (*Dashboard, error) { - wireReq, err := migrateDashboardRequestToWire(req) +// Deprecated: Legacy dashboard migration is no longer supported. Use Lakeview +// (AI/BI) dashboards instead. +func (c *internalClient) MigrateDashboard(ctx context.Context, req MigrateDashboardRequest, opts ...call.Option) (*Dashboard, error) { + wireReq, err := migrateDashboardRequestToWire(&req) if err != nil { return nil, err } @@ -1147,8 +1233,10 @@ func (c *internalClient) MigrateDashboard(ctx context.Context, req *MigrateDashb } // Publish the current draft dashboard. -func (c *internalClient) PublishDashboard(ctx context.Context, req *PublishDashboardRequest, opts ...call.Option) (*PublishedDashboard, error) { - wireReq, err := publishDashboardRequestToWire(req) +// +// Requires the Databricks SQL access entitlement. +func (c *internalClient) PublishDashboard(ctx context.Context, req PublishDashboardRequest, opts ...call.Option) (*PublishedDashboard, error) { + wireReq, err := publishDashboardRequestToWire(&req) if err != nil { return nil, err } @@ -1169,7 +1257,11 @@ func (c *internalClient) PublishDashboard(ctx context.Context, req *PublishDashb } pb := pathBuilder{} pb.literal("/api/2.0/lakeview/dashboards/") - pb.singleSegment(*req.DashboardId) + if req.DashboardId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DashboardId) + } pb.literal("/published") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1217,8 +1309,10 @@ func (c *internalClient) PublishDashboard(ctx context.Context, req *PublishDashb } // Revert a dashboard's definition in draft mode to the last published version. -func (c *internalClient) RevertDashboard(ctx context.Context, req *RevertDashboardRequest, opts ...call.Option) (*RevertDashboardResponse, error) { - wireReq, err := revertDashboardRequestToWire(req) +// +// Requires the Databricks SQL access entitlement. +func (c *internalClient) RevertDashboard(ctx context.Context, req RevertDashboardRequest, opts ...call.Option) (*RevertDashboardResponse, error) { + wireReq, err := revertDashboardRequestToWire(&req) if err != nil { return nil, err } @@ -1239,7 +1333,11 @@ func (c *internalClient) RevertDashboard(ctx context.Context, req *RevertDashboa } pb := pathBuilder{} pb.literal("/api/2.0/lakeview/dashboards/") - pb.singleSegment(*req.DashboardId) + if req.DashboardId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DashboardId) + } pb.literal("/revert") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1287,7 +1385,9 @@ func (c *internalClient) RevertDashboard(ctx context.Context, req *RevertDashboa } // Trash a dashboard. -func (c *internalClient) TrashDashboard(ctx context.Context, req *TrashDashboardRequest, opts ...call.Option) (*TrashDashboardResponse, error) { +// +// Requires the Databricks SQL access entitlement. +func (c *internalClient) TrashDashboard(ctx context.Context, req TrashDashboardRequest, opts ...call.Option) (*TrashDashboardResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1301,7 +1401,11 @@ func (c *internalClient) TrashDashboard(ctx context.Context, req *TrashDashboard } pb := pathBuilder{} pb.literal("/api/2.0/lakeview/dashboards/") - pb.singleSegment(*req.DashboardId) + if req.DashboardId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DashboardId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1341,7 +1445,9 @@ func (c *internalClient) TrashDashboard(ctx context.Context, req *TrashDashboard } // Unpublish the dashboard. -func (c *internalClient) UnpublishDashboard(ctx context.Context, req *UnpublishDashboardRequest, opts ...call.Option) (*UnpublishDashboardResponse, error) { +// +// Requires the Databricks SQL access entitlement. +func (c *internalClient) UnpublishDashboard(ctx context.Context, req UnpublishDashboardRequest, opts ...call.Option) (*UnpublishDashboardResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1355,7 +1461,11 @@ func (c *internalClient) UnpublishDashboard(ctx context.Context, req *UnpublishD } pb := pathBuilder{} pb.literal("/api/2.0/lakeview/dashboards/") - pb.singleSegment(*req.DashboardId) + if req.DashboardId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DashboardId) + } pb.literal("/published") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1396,8 +1506,10 @@ func (c *internalClient) UnpublishDashboard(ctx context.Context, req *UnpublishD } // Update a draft dashboard. -func (c *internalClient) UpdateDashboard(ctx context.Context, req *UpdateDashboardRequest, opts ...call.Option) (*Dashboard, error) { - wireReq, err := updateDashboardRequestToWire(req) +// +// Requires the Databricks SQL access entitlement. +func (c *internalClient) UpdateDashboard(ctx context.Context, req UpdateDashboardRequest, opts ...call.Option) (*Dashboard, error) { + wireReq, err := updateDashboardRequestToWire(&req) if err != nil { return nil, err } @@ -1418,7 +1530,11 @@ func (c *internalClient) UpdateDashboard(ctx context.Context, req *UpdateDashboa } pb := pathBuilder{} pb.literal("/api/2.0/lakeview/dashboards/") - pb.singleSegment(*req.Dashboard.DashboardId) + if req.Dashboard == nil || req.Dashboard.DashboardId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Dashboard.DashboardId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "dataset_catalog", wireReq.DatasetCatalog); err != nil { @@ -1471,8 +1587,8 @@ func (c *internalClient) UpdateDashboard(ctx context.Context, req *UpdateDashboa } // Update dashboard schedule. -func (c *internalClient) UpdateSchedule(ctx context.Context, req *UpdateScheduleRequest, opts ...call.Option) (*Schedule, error) { - wireReq, err := updateScheduleRequestToWire(req) +func (c *internalClient) UpdateSchedule(ctx context.Context, req UpdateScheduleRequest, opts ...call.Option) (*Schedule, error) { + wireReq, err := updateScheduleRequestToWire(&req) if err != nil { return nil, err } @@ -1493,9 +1609,17 @@ func (c *internalClient) UpdateSchedule(ctx context.Context, req *UpdateSchedule } pb := pathBuilder{} pb.literal("/api/2.0/lakeview/dashboards/") - pb.singleSegment(*req.Schedule.DashboardId) + if req.Schedule == nil || req.Schedule.DashboardId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Schedule.DashboardId) + } pb.literal("/schedules/") - pb.singleSegment(*req.Schedule.ScheduleId) + if req.Schedule == nil || req.Schedule.ScheduleId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Schedule.ScheduleId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/lakeview/v1/genhelper.go b/lakeview/v1/genhelper.go old mode 100755 new mode 100644 index dc476ae..0698f54 --- a/lakeview/v1/genhelper.go +++ b/lakeview/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/lakeview/v1/wire.go b/lakeview/v1/wire.go old mode 100755 new mode 100644 index ac6b124..97a87bb --- a/lakeview/v1/wire.go +++ b/lakeview/v1/wire.go @@ -3,11 +3,57 @@ package lakeview import ( + "bytes" + "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type authorizationDetailsWire struct { Type *string `json:"type,omitempty"` ResourceName *string `json:"resource_name,omitempty"` @@ -505,7 +551,7 @@ type subscriptionWire struct { ScheduleId *string `json:"schedule_id,omitempty"` DashboardId *string `json:"dashboard_id,omitempty"` Subscriber *subscription_SubscriberWire `json:"subscriber,omitempty"` - CreatedByUserId *int64 `json:"created_by_user_id,omitempty"` + CreatedByUserId *wireInt64 `json:"created_by_user_id,omitempty"` Etag *string `json:"etag,omitempty"` CreateTime *types.Time `json:"create_time,omitempty"` UpdateTime *types.Time `json:"update_time,omitempty"` @@ -520,12 +566,16 @@ func subscriptionToWire(v *Subscription) (*subscriptionWire, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "Subscription.Subscriber", err) } + createdByUserIdWireValue, err := int64ToWire(v.CreatedByUserId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Subscription.CreatedByUserId", err) + } return &subscriptionWire{ SubscriptionId: v.SubscriptionId, ScheduleId: v.ScheduleId, DashboardId: v.DashboardId, Subscriber: subscriberWireValue, - CreatedByUserId: v.CreatedByUserId, + CreatedByUserId: createdByUserIdWireValue, Etag: v.Etag, CreateTime: v.CreateTime, UpdateTime: v.UpdateTime, @@ -541,12 +591,16 @@ func subscriptionFromWire(w *subscriptionWire) (*Subscription, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "Subscription.Subscriber", err) } + createdByUserIdPublicValue, err := int64FromWire(w.CreatedByUserId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Subscription.CreatedByUserId", err) + } return &Subscription{ SubscriptionId: w.SubscriptionId, ScheduleId: w.ScheduleId, DashboardId: w.DashboardId, Subscriber: subscriberPublicValue, - CreatedByUserId: w.CreatedByUserId, + CreatedByUserId: createdByUserIdPublicValue, Etag: w.Etag, CreateTime: w.CreateTime, UpdateTime: w.UpdateTime, @@ -618,15 +672,19 @@ func subscription_Subscriber_DestinationFromWire(w *subscription_Subscriber_Dest } type subscription_Subscriber_UserWire struct { - UserId *int64 `json:"user_id,omitempty"` + UserId *wireInt64 `json:"user_id,omitempty"` } func subscription_Subscriber_UserToWire(v *Subscription_Subscriber_User) (*subscription_Subscriber_UserWire, error) { if v == nil { return nil, nil } + userIdWireValue, err := int64ToWire(v.UserId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Subscription_Subscriber_User.UserId", err) + } return &subscription_Subscriber_UserWire{ - UserId: v.UserId, + UserId: userIdWireValue, }, nil } @@ -634,8 +692,12 @@ func subscription_Subscriber_UserFromWire(w *subscription_Subscriber_UserWire) ( if w == nil { return nil, nil } + userIdPublicValue, err := int64FromWire(w.UserId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Subscription_Subscriber_User.UserId", err) + } return &Subscription_Subscriber_User{ - UserId: w.UserId, + UserId: userIdPublicValue, }, nil } diff --git a/logdelivery/CHANGELOG.md b/logdelivery/CHANGELOG.md index 6224c04..19f237c 100644 --- a/logdelivery/CHANGELOG.md +++ b/logdelivery/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/logdelivery/go.mod b/logdelivery/go.mod index 7e83bb1..fd13b59 100644 --- a/logdelivery/go.mod +++ b/logdelivery/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/logdelivery/internal/version.go b/logdelivery/internal/version.go index 0740296..7cd3c71 100644 --- a/logdelivery/internal/version.go +++ b/logdelivery/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-logdelivery" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/logdelivery/v1/client.go b/logdelivery/v1/client.go old mode 100755 new mode 100644 index 34b4c4b..81f15d5 --- a/logdelivery/v1/client.go +++ b/logdelivery/v1/client.go @@ -100,8 +100,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // [Configure audit logging]: https://docs.databricks.com/administration-guide/account-settings/audit-logs.html // [Deliver and access billable usage logs]: https://docs.databricks.com/administration-guide/account-settings/billable-usage-delivery.html // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateLogDeliveryConfiguration(ctx context.Context, req *CreateLogDeliveryConfigurationRequest, opts ...call.Option) (*CreateLogDeliveryConfigurationResponse, error) { - wireReq, err := createLogDeliveryConfigurationRequestToWire(req) +func (c *internalClient) CreateLogDeliveryConfiguration(ctx context.Context, req CreateLogDeliveryConfigurationRequest, opts ...call.Option) (*CreateLogDeliveryConfigurationResponse, error) { + wireReq, err := createLogDeliveryConfigurationRequestToWire(&req) if err != nil { return nil, err } @@ -170,7 +170,7 @@ func (c *internalClient) CreateLogDeliveryConfiguration(ctx context.Context, req // Gets a log delivery configuration object for an account, both // specified by ID. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetLogDeliveryConfiguration(ctx context.Context, req *GetLogDeliveryConfigurationRequest, opts ...call.Option) (*GetLogDeliveryConfigurationResponse, error) { +func (c *internalClient) GetLogDeliveryConfiguration(ctx context.Context, req GetLogDeliveryConfigurationRequest, opts ...call.Option) (*GetLogDeliveryConfigurationResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -187,7 +187,11 @@ func (c *internalClient) GetLogDeliveryConfiguration(ctx context.Context, req *G pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/log-delivery/") - pb.singleSegment(*req.ConfigId) + if req.ConfigId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ConfigId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -235,8 +239,8 @@ func (c *internalClient) GetLogDeliveryConfiguration(ctx context.Context, req *G // Gets all log delivery configurations associated with an account // specified by ID. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListLogDeliveryConfiguration(ctx context.Context, req *ListLogDeliveryConfigurationRequest, opts ...call.Option) (*ListLogDeliveryConfigurationResponse, error) { - wireReq, err := listLogDeliveryConfigurationRequestToWire(req) +func (c *internalClient) ListLogDeliveryConfiguration(ctx context.Context, req ListLogDeliveryConfigurationRequest, opts ...call.Option) (*ListLogDeliveryConfigurationResponse, error) { + wireReq, err := listLogDeliveryConfigurationRequestToWire(&req) if err != nil { return nil, err } @@ -319,7 +323,7 @@ func (c *internalClient) ListLogDeliveryConfiguration(ctx context.Context, req * // // For example: // -// for item, err := range c.ListLogDeliveryConfigurationIter(ctx, &ListLogDeliveryConfigurationRequest{}) { +// for item, err := range c.ListLogDeliveryConfigurationIter(ctx, ListLogDeliveryConfigurationRequest{}) { // if err != nil { // return err // } @@ -331,16 +335,13 @@ func (c *internalClient) ListLogDeliveryConfiguration(ctx context.Context, req * // // Callers who need custom pagination logic should use // ListLogDeliveryConfiguration directly. -func (c *internalClient) ListLogDeliveryConfigurationIter(ctx context.Context, req *ListLogDeliveryConfigurationRequest, opts ...call.Option) iter.Seq2[*LogDeliveryConfiguration, error] { +func (c *internalClient) ListLogDeliveryConfigurationIter(ctx context.Context, req ListLogDeliveryConfigurationRequest, opts ...call.Option) iter.Seq2[*LogDeliveryConfiguration, error] { return func(yield func(*LogDeliveryConfiguration, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListLogDeliveryConfigurationRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListLogDeliveryConfiguration(ctx, &pageReq, opts...) + resp, err := c.ListLogDeliveryConfiguration(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -364,8 +365,8 @@ func (c *internalClient) ListLogDeliveryConfigurationIter(ctx context.Context, r // if this would violate the delivery configuration limits described under // [Create log delivery](:method:LogDelivery/Create). // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdateLogDeliveryConfiguration(ctx context.Context, req *UpdateLogDeliveryConfigurationRequest, opts ...call.Option) (*UpdateLogDeliveryConfigurationResponse, error) { - wireReq, err := updateLogDeliveryConfigurationRequestToWire(req) +func (c *internalClient) UpdateLogDeliveryConfiguration(ctx context.Context, req UpdateLogDeliveryConfigurationRequest, opts ...call.Option) (*UpdateLogDeliveryConfigurationResponse, error) { + wireReq, err := updateLogDeliveryConfigurationRequestToWire(&req) if err != nil { return nil, err } @@ -389,7 +390,11 @@ func (c *internalClient) UpdateLogDeliveryConfiguration(ctx context.Context, req pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/log-delivery/") - pb.singleSegment(*req.ConfigId) + if req.ConfigId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ConfigId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/logdelivery/v1/genhelper.go b/logdelivery/v1/genhelper.go old mode 100755 new mode 100644 index 1eb8ded..80d92ef --- a/logdelivery/v1/genhelper.go +++ b/logdelivery/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/logdelivery/v1/wire.go b/logdelivery/v1/wire.go old mode 100755 new mode 100644 index 377b12b..672d3fb --- a/logdelivery/v1/wire.go +++ b/logdelivery/v1/wire.go @@ -3,9 +3,55 @@ package logdelivery import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type createLogDeliveryConfigurationParamsWire struct { ConfigId *string `json:"config_id,omitempty"` ConfigName *string `json:"config_name,omitempty"` @@ -14,12 +60,12 @@ type createLogDeliveryConfigurationParamsWire struct { AccountId *string `json:"account_id,omitempty"` CredentialsId *string `json:"credentials_id,omitempty"` StorageConfigurationId *string `json:"storage_configuration_id,omitempty"` - WorkspaceIdsFilter []int64 `json:"workspace_ids_filter,omitempty"` + WorkspaceIdsFilter []wireInt64 `json:"workspace_ids_filter,omitempty"` DeliveryPathPrefix *string `json:"delivery_path_prefix,omitempty"` DeliveryStartTime *string `json:"delivery_start_time,omitempty"` Status LogDeliveryConfigStatus `json:"status,omitempty"` - CreationTime *int64 `json:"creation_time,omitempty"` - UpdateTime *int64 `json:"update_time,omitempty"` + CreationTime *wireInt64 `json:"creation_time,omitempty"` + UpdateTime *wireInt64 `json:"update_time,omitempty"` LogDeliveryStatus *logDeliveryStatusWire `json:"log_delivery_status,omitempty"` } @@ -27,6 +73,18 @@ func createLogDeliveryConfigurationParamsToWire(v *CreateLogDeliveryConfiguratio if v == nil { return nil, nil } + workspaceIdsFilterWireValue, err := convertSlice(v.WorkspaceIdsFilter, int64ToWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateLogDeliveryConfigurationParams.WorkspaceIdsFilter", err) + } + creationTimeWireValue, err := int64ToWire(v.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateLogDeliveryConfigurationParams.CreationTime", err) + } + updateTimeWireValue, err := int64ToWire(v.UpdateTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateLogDeliveryConfigurationParams.UpdateTime", err) + } logDeliveryStatusWireValue, err := logDeliveryStatusToWire(v.LogDeliveryStatus) if err != nil { return nil, fmt.Errorf("%s: %w", "CreateLogDeliveryConfigurationParams.LogDeliveryStatus", err) @@ -39,12 +97,12 @@ func createLogDeliveryConfigurationParamsToWire(v *CreateLogDeliveryConfiguratio AccountId: v.AccountId, CredentialsId: v.CredentialsId, StorageConfigurationId: v.StorageConfigurationId, - WorkspaceIdsFilter: v.WorkspaceIdsFilter, + WorkspaceIdsFilter: workspaceIdsFilterWireValue, DeliveryPathPrefix: v.DeliveryPathPrefix, DeliveryStartTime: v.DeliveryStartTime, Status: v.Status, - CreationTime: v.CreationTime, - UpdateTime: v.UpdateTime, + CreationTime: creationTimeWireValue, + UpdateTime: updateTimeWireValue, LogDeliveryStatus: logDeliveryStatusWireValue, }, nil } @@ -148,12 +206,12 @@ type logDeliveryConfigurationWire struct { AccountId *string `json:"account_id,omitempty"` CredentialsId *string `json:"credentials_id,omitempty"` StorageConfigurationId *string `json:"storage_configuration_id,omitempty"` - WorkspaceIdsFilter []int64 `json:"workspace_ids_filter,omitempty"` + WorkspaceIdsFilter []wireInt64 `json:"workspace_ids_filter,omitempty"` DeliveryPathPrefix *string `json:"delivery_path_prefix,omitempty"` DeliveryStartTime *string `json:"delivery_start_time,omitempty"` Status LogDeliveryConfigStatus `json:"status,omitempty"` - CreationTime *int64 `json:"creation_time,omitempty"` - UpdateTime *int64 `json:"update_time,omitempty"` + CreationTime *wireInt64 `json:"creation_time,omitempty"` + UpdateTime *wireInt64 `json:"update_time,omitempty"` LogDeliveryStatus *logDeliveryStatusWire `json:"log_delivery_status,omitempty"` } @@ -161,6 +219,18 @@ func logDeliveryConfigurationFromWire(w *logDeliveryConfigurationWire) (*LogDeli if w == nil { return nil, nil } + workspaceIdsFilterPublicValue, err := convertSlice(w.WorkspaceIdsFilter, int64FromWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "LogDeliveryConfiguration.WorkspaceIdsFilter", err) + } + creationTimePublicValue, err := int64FromWire(w.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "LogDeliveryConfiguration.CreationTime", err) + } + updateTimePublicValue, err := int64FromWire(w.UpdateTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "LogDeliveryConfiguration.UpdateTime", err) + } logDeliveryStatusPublicValue, err := logDeliveryStatusFromWire(w.LogDeliveryStatus) if err != nil { return nil, fmt.Errorf("%s: %w", "LogDeliveryConfiguration.LogDeliveryStatus", err) @@ -173,12 +243,12 @@ func logDeliveryConfigurationFromWire(w *logDeliveryConfigurationWire) (*LogDeli AccountId: w.AccountId, CredentialsId: w.CredentialsId, StorageConfigurationId: w.StorageConfigurationId, - WorkspaceIdsFilter: w.WorkspaceIdsFilter, + WorkspaceIdsFilter: workspaceIdsFilterPublicValue, DeliveryPathPrefix: w.DeliveryPathPrefix, DeliveryStartTime: w.DeliveryStartTime, Status: w.Status, - CreationTime: w.CreationTime, - UpdateTime: w.UpdateTime, + CreationTime: creationTimePublicValue, + UpdateTime: updateTimePublicValue, LogDeliveryStatus: logDeliveryStatusPublicValue, }, nil } diff --git a/marketplaces/CHANGELOG.md b/marketplaces/CHANGELOG.md index 6224c04..19f237c 100644 --- a/marketplaces/CHANGELOG.md +++ b/marketplaces/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/marketplaces/go.mod b/marketplaces/go.mod index 665baa3..50ed355 100644 --- a/marketplaces/go.mod +++ b/marketplaces/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/marketplaces/internal/version.go b/marketplaces/internal/version.go index f06a22d..6abdabd 100644 --- a/marketplaces/internal/version.go +++ b/marketplaces/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-marketplaces" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/marketplaces/v1/client.go b/marketplaces/v1/client.go old mode 100755 new mode 100644 index 2a0ec9e..7784a8c --- a/marketplaces/v1/client.go +++ b/marketplaces/v1/client.go @@ -76,8 +76,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Batch get a published listing in the Databricks Marketplace that the consumer // has access to. -func (c *internalClient) BatchGetListings(ctx context.Context, req *BatchGetListingsRequest, opts ...call.Option) (*BatchGetListingsResponse, error) { - wireReq, err := batchGetListingsRequestToWire(req) +func (c *internalClient) BatchGetListings(ctx context.Context, req BatchGetListingsRequest, opts ...call.Option) (*BatchGetListingsResponse, error) { + wireReq, err := batchGetListingsRequestToWire(&req) if err != nil { return nil, err } @@ -141,8 +141,8 @@ func (c *internalClient) BatchGetListings(ctx context.Context, req *BatchGetList // Batch get a provider in the Databricks Marketplace with at least one visible // listing. -func (c *internalClient) BatchGetProviders(ctx context.Context, req *BatchGetProvidersRequest, opts ...call.Option) (*BatchGetProvidersResponse, error) { - wireReq, err := batchGetProvidersRequestToWire(req) +func (c *internalClient) BatchGetProviders(ctx context.Context, req BatchGetProvidersRequest, opts ...call.Option) (*BatchGetProvidersResponse, error) { + wireReq, err := batchGetProvidersRequestToWire(&req) if err != nil { return nil, err } @@ -205,8 +205,8 @@ func (c *internalClient) BatchGetProviders(ctx context.Context, req *BatchGetPro } // Create a personalization request for a listing. -func (c *internalClient) CreatePersonalizationRequest(ctx context.Context, req *CreatePersonalizationRequest, opts ...call.Option) (*CreatePersonalizationResponse, error) { - wireReq, err := createPersonalizationRequestToWire(req) +func (c *internalClient) CreatePersonalizationRequest(ctx context.Context, req CreatePersonalizationRequest, opts ...call.Option) (*CreatePersonalizationResponse, error) { + wireReq, err := createPersonalizationRequestToWire(&req) if err != nil { return nil, err } @@ -227,7 +227,11 @@ func (c *internalClient) CreatePersonalizationRequest(ctx context.Context, req * } pb := pathBuilder{} pb.literal("/api/2.1/marketplace-consumer/listings/") - pb.singleSegment(*req.ListingId) + if req.ListingId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ListingId) + } pb.literal("/personalization-requests") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -275,8 +279,8 @@ func (c *internalClient) CreatePersonalizationRequest(ctx context.Context, req * } // List all installations for a particular listing. -func (c *internalClient) GetInstallationDetails(ctx context.Context, req *GetInstallationDetailsRequest, opts ...call.Option) (*ListInstallationsResponse, error) { - wireReq, err := getInstallationDetailsRequestToWire(req) +func (c *internalClient) GetInstallationDetails(ctx context.Context, req GetInstallationDetailsRequest, opts ...call.Option) (*ListInstallationsResponse, error) { + wireReq, err := getInstallationDetailsRequestToWire(&req) if err != nil { return nil, err } @@ -293,7 +297,11 @@ func (c *internalClient) GetInstallationDetails(ctx context.Context, req *GetIns } pb := pathBuilder{} pb.literal("/api/2.1/marketplace-consumer/listings/") - pb.singleSegment(*req.ListingId) + if req.ListingId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ListingId) + } pb.literal("/installations") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -350,7 +358,7 @@ func (c *internalClient) GetInstallationDetails(ctx context.Context, req *GetIns // // For example: // -// for item, err := range c.GetInstallationDetailsIter(ctx, &GetInstallationDetailsRequest{}) { +// for item, err := range c.GetInstallationDetailsIter(ctx, GetInstallationDetailsRequest{}) { // if err != nil { // return err // } @@ -362,16 +370,13 @@ func (c *internalClient) GetInstallationDetails(ctx context.Context, req *GetIns // // Callers who need custom pagination logic should use // GetInstallationDetails directly. -func (c *internalClient) GetInstallationDetailsIter(ctx context.Context, req *GetInstallationDetailsRequest, opts ...call.Option) iter.Seq2[*InstallationDetail, error] { +func (c *internalClient) GetInstallationDetailsIter(ctx context.Context, req GetInstallationDetailsRequest, opts ...call.Option) iter.Seq2[*InstallationDetail, error] { return func(yield func(*InstallationDetail, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := GetInstallationDetailsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.GetInstallationDetails(ctx, &pageReq, opts...) + resp, err := c.GetInstallationDetails(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -390,8 +395,8 @@ func (c *internalClient) GetInstallationDetailsIter(ctx context.Context, req *Ge } // Get a high level preview of the metadata of listing installable content. -func (c *internalClient) GetListingContent(ctx context.Context, req *GetListingContentMetadataRequest, opts ...call.Option) (*GetListingContentMetadataResponse, error) { - wireReq, err := getListingContentMetadataRequestToWire(req) +func (c *internalClient) GetListingContent(ctx context.Context, req GetListingContentMetadataRequest, opts ...call.Option) (*GetListingContentMetadataResponse, error) { + wireReq, err := getListingContentMetadataRequestToWire(&req) if err != nil { return nil, err } @@ -408,7 +413,11 @@ func (c *internalClient) GetListingContent(ctx context.Context, req *GetListingC } pb := pathBuilder{} pb.literal("/api/2.1/marketplace-consumer/listings/") - pb.singleSegment(*req.ListingId) + if req.ListingId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ListingId) + } pb.literal("/content") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -465,7 +474,7 @@ func (c *internalClient) GetListingContent(ctx context.Context, req *GetListingC // // For example: // -// for item, err := range c.GetListingContentIter(ctx, &GetListingContentMetadataRequest{}) { +// for item, err := range c.GetListingContentIter(ctx, GetListingContentMetadataRequest{}) { // if err != nil { // return err // } @@ -477,16 +486,13 @@ func (c *internalClient) GetListingContent(ctx context.Context, req *GetListingC // // Callers who need custom pagination logic should use // GetListingContent directly. -func (c *internalClient) GetListingContentIter(ctx context.Context, req *GetListingContentMetadataRequest, opts ...call.Option) iter.Seq2[*SharedDataObject, error] { +func (c *internalClient) GetListingContentIter(ctx context.Context, req GetListingContentMetadataRequest, opts ...call.Option) iter.Seq2[*SharedDataObject, error] { return func(yield func(*SharedDataObject, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := GetListingContentMetadataRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.GetListingContent(ctx, &pageReq, opts...) + resp, err := c.GetListingContent(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -506,7 +512,7 @@ func (c *internalClient) GetListingContentIter(ctx context.Context, req *GetList // Get the personalization request for a listing. Each consumer can make at // *most* one personalization request for a listing. -func (c *internalClient) GetPersonalizationRequestsForConsumer(ctx context.Context, req *GetPersonalizationRequestsForConsumerRequest, opts ...call.Option) (*GetPersonalizationRequestsForConsumerResponse, error) { +func (c *internalClient) GetPersonalizationRequestsForConsumer(ctx context.Context, req GetPersonalizationRequestsForConsumerRequest, opts ...call.Option) (*GetPersonalizationRequestsForConsumerResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -520,7 +526,11 @@ func (c *internalClient) GetPersonalizationRequestsForConsumer(ctx context.Conte } pb := pathBuilder{} pb.literal("/api/2.1/marketplace-consumer/listings/") - pb.singleSegment(*req.ListingId) + if req.ListingId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ListingId) + } pb.literal("/personalization-requests") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -568,7 +578,7 @@ func (c *internalClient) GetPersonalizationRequestsForConsumer(ctx context.Conte // Get a published listing in the Databricks Marketplace that the consumer has // access to. -func (c *internalClient) GetPublishedListingForConsumer(ctx context.Context, req *GetPublishedListingForConsumerRequest, opts ...call.Option) (*GetPublishedListingForConsumerResponse, error) { +func (c *internalClient) GetPublishedListingForConsumer(ctx context.Context, req GetPublishedListingForConsumerRequest, opts ...call.Option) (*GetPublishedListingForConsumerResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -582,7 +592,11 @@ func (c *internalClient) GetPublishedListingForConsumer(ctx context.Context, req } pb := pathBuilder{} pb.literal("/api/2.1/marketplace-consumer/listings/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -629,7 +643,7 @@ func (c *internalClient) GetPublishedListingForConsumer(ctx context.Context, req // Get a provider in the Databricks Marketplace with at least one visible // listing. -func (c *internalClient) GetPublishedProviderForConsumer(ctx context.Context, req *GetPublishedProviderForConsumerRequest, opts ...call.Option) (*GetPublishedProviderForConsumerResponse, error) { +func (c *internalClient) GetPublishedProviderForConsumer(ctx context.Context, req GetPublishedProviderForConsumerRequest, opts ...call.Option) (*GetPublishedProviderForConsumerResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -643,7 +657,11 @@ func (c *internalClient) GetPublishedProviderForConsumer(ctx context.Context, re } pb := pathBuilder{} pb.literal("/api/2.1/marketplace-consumer/providers/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -689,8 +707,8 @@ func (c *internalClient) GetPublishedProviderForConsumer(ctx context.Context, re } // Install payload associated with a Databricks Marketplace listing. -func (c *internalClient) InstallListing(ctx context.Context, req *CreateInstallationRequest, opts ...call.Option) (*CreateInstallationResponse, error) { - wireReq, err := createInstallationRequestToWire(req) +func (c *internalClient) InstallListing(ctx context.Context, req CreateInstallationRequest, opts ...call.Option) (*CreateInstallationResponse, error) { + wireReq, err := createInstallationRequestToWire(&req) if err != nil { return nil, err } @@ -711,7 +729,11 @@ func (c *internalClient) InstallListing(ctx context.Context, req *CreateInstalla } pb := pathBuilder{} pb.literal("/api/2.1/marketplace-consumer/listings/") - pb.singleSegment(*req.ListingId) + if req.ListingId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ListingId) + } pb.literal("/installations") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -759,8 +781,8 @@ func (c *internalClient) InstallListing(ctx context.Context, req *CreateInstalla } // List all installations across all listings. -func (c *internalClient) ListInstallations(ctx context.Context, req *ListInstallationsRequest, opts ...call.Option) (*ListAllInstallationsResponse, error) { - wireReq, err := listInstallationsRequestToWire(req) +func (c *internalClient) ListInstallations(ctx context.Context, req ListInstallationsRequest, opts ...call.Option) (*ListAllInstallationsResponse, error) { + wireReq, err := listInstallationsRequestToWire(&req) if err != nil { return nil, err } @@ -830,7 +852,7 @@ func (c *internalClient) ListInstallations(ctx context.Context, req *ListInstall // // For example: // -// for item, err := range c.ListInstallationsIter(ctx, &ListInstallationsRequest{}) { +// for item, err := range c.ListInstallationsIter(ctx, ListInstallationsRequest{}) { // if err != nil { // return err // } @@ -842,16 +864,13 @@ func (c *internalClient) ListInstallations(ctx context.Context, req *ListInstall // // Callers who need custom pagination logic should use // ListInstallations directly. -func (c *internalClient) ListInstallationsIter(ctx context.Context, req *ListInstallationsRequest, opts ...call.Option) iter.Seq2[*InstallationDetail, error] { +func (c *internalClient) ListInstallationsIter(ctx context.Context, req ListInstallationsRequest, opts ...call.Option) iter.Seq2[*InstallationDetail, error] { return func(yield func(*InstallationDetail, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListInstallationsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListInstallations(ctx, &pageReq, opts...) + resp, err := c.ListInstallations(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -874,8 +893,8 @@ func (c *internalClient) ListInstallationsIter(ctx context.Context, req *ListIns // attached share or git repo. Only one of these fields will be present. // Personalized installations contain metadata about the attached share or git // repo, as well as the Delta Sharing recipient type. -func (c *internalClient) ListListingFulfillments(ctx context.Context, req *ListListingFulfillmentsRequest, opts ...call.Option) (*ListFulfillmentsResponse, error) { - wireReq, err := listListingFulfillmentsRequestToWire(req) +func (c *internalClient) ListListingFulfillments(ctx context.Context, req ListListingFulfillmentsRequest, opts ...call.Option) (*ListFulfillmentsResponse, error) { + wireReq, err := listListingFulfillmentsRequestToWire(&req) if err != nil { return nil, err } @@ -892,7 +911,11 @@ func (c *internalClient) ListListingFulfillments(ctx context.Context, req *ListL } pb := pathBuilder{} pb.literal("/api/2.1/marketplace-consumer/listings/") - pb.singleSegment(*req.ListingId) + if req.ListingId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ListingId) + } pb.literal("/fulfillments") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -949,7 +972,7 @@ func (c *internalClient) ListListingFulfillments(ctx context.Context, req *ListL // // For example: // -// for item, err := range c.ListListingFulfillmentsIter(ctx, &ListListingFulfillmentsRequest{}) { +// for item, err := range c.ListListingFulfillmentsIter(ctx, ListListingFulfillmentsRequest{}) { // if err != nil { // return err // } @@ -961,16 +984,13 @@ func (c *internalClient) ListListingFulfillments(ctx context.Context, req *ListL // // Callers who need custom pagination logic should use // ListListingFulfillments directly. -func (c *internalClient) ListListingFulfillmentsIter(ctx context.Context, req *ListListingFulfillmentsRequest, opts ...call.Option) iter.Seq2[*ListingFulfillment, error] { +func (c *internalClient) ListListingFulfillmentsIter(ctx context.Context, req ListListingFulfillmentsRequest, opts ...call.Option) iter.Seq2[*ListingFulfillment, error] { return func(yield func(*ListingFulfillment, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListListingFulfillmentsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListListingFulfillments(ctx, &pageReq, opts...) + resp, err := c.ListListingFulfillments(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -989,8 +1009,8 @@ func (c *internalClient) ListListingFulfillmentsIter(ctx context.Context, req *L } // List personalization requests for a consumer across all listings. -func (c *internalClient) ListPersonalizationRequestsForConsumer(ctx context.Context, req *ListPersonalizationRequestsForConsumerRequest, opts ...call.Option) (*GetAllPersonalizationRequestsForConsumerResponse, error) { - wireReq, err := listPersonalizationRequestsForConsumerRequestToWire(req) +func (c *internalClient) ListPersonalizationRequestsForConsumer(ctx context.Context, req ListPersonalizationRequestsForConsumerRequest, opts ...call.Option) (*GetAllPersonalizationRequestsForConsumerResponse, error) { + wireReq, err := listPersonalizationRequestsForConsumerRequestToWire(&req) if err != nil { return nil, err } @@ -1060,7 +1080,7 @@ func (c *internalClient) ListPersonalizationRequestsForConsumer(ctx context.Cont // // For example: // -// for item, err := range c.ListPersonalizationRequestsForConsumerIter(ctx, &ListPersonalizationRequestsForConsumerRequest{}) { +// for item, err := range c.ListPersonalizationRequestsForConsumerIter(ctx, ListPersonalizationRequestsForConsumerRequest{}) { // if err != nil { // return err // } @@ -1072,16 +1092,13 @@ func (c *internalClient) ListPersonalizationRequestsForConsumer(ctx context.Cont // // Callers who need custom pagination logic should use // ListPersonalizationRequestsForConsumer directly. -func (c *internalClient) ListPersonalizationRequestsForConsumerIter(ctx context.Context, req *ListPersonalizationRequestsForConsumerRequest, opts ...call.Option) iter.Seq2[*PersonalizationRequest, error] { +func (c *internalClient) ListPersonalizationRequestsForConsumerIter(ctx context.Context, req ListPersonalizationRequestsForConsumerRequest, opts ...call.Option) iter.Seq2[*PersonalizationRequest, error] { return func(yield func(*PersonalizationRequest, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListPersonalizationRequestsForConsumerRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListPersonalizationRequestsForConsumer(ctx, &pageReq, opts...) + resp, err := c.ListPersonalizationRequestsForConsumer(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1101,8 +1118,8 @@ func (c *internalClient) ListPersonalizationRequestsForConsumerIter(ctx context. // List all published listings in the Databricks Marketplace that the consumer // has access to. -func (c *internalClient) ListPublishedListingsForConsumer(ctx context.Context, req *ListPublishedListingsForConsumerRequest, opts ...call.Option) (*GetPublishedListingsForConsumerResponse, error) { - wireReq, err := listPublishedListingsForConsumerRequestToWire(req) +func (c *internalClient) ListPublishedListingsForConsumer(ctx context.Context, req ListPublishedListingsForConsumerRequest, opts ...call.Option) (*GetPublishedListingsForConsumerResponse, error) { + wireReq, err := listPublishedListingsForConsumerRequestToWire(&req) if err != nil { return nil, err } @@ -1193,7 +1210,7 @@ func (c *internalClient) ListPublishedListingsForConsumer(ctx context.Context, r // // For example: // -// for item, err := range c.ListPublishedListingsForConsumerIter(ctx, &ListPublishedListingsForConsumerRequest{}) { +// for item, err := range c.ListPublishedListingsForConsumerIter(ctx, ListPublishedListingsForConsumerRequest{}) { // if err != nil { // return err // } @@ -1205,16 +1222,13 @@ func (c *internalClient) ListPublishedListingsForConsumer(ctx context.Context, r // // Callers who need custom pagination logic should use // ListPublishedListingsForConsumer directly. -func (c *internalClient) ListPublishedListingsForConsumerIter(ctx context.Context, req *ListPublishedListingsForConsumerRequest, opts ...call.Option) iter.Seq2[*Listing, error] { +func (c *internalClient) ListPublishedListingsForConsumerIter(ctx context.Context, req ListPublishedListingsForConsumerRequest, opts ...call.Option) iter.Seq2[*Listing, error] { return func(yield func(*Listing, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListPublishedListingsForConsumerRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListPublishedListingsForConsumer(ctx, &pageReq, opts...) + resp, err := c.ListPublishedListingsForConsumer(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1234,8 +1248,8 @@ func (c *internalClient) ListPublishedListingsForConsumerIter(ctx context.Contex // List all providers in the Databricks Marketplace with at least one visible // listing. -func (c *internalClient) ListPublishedProvidersForConsumer(ctx context.Context, req *ListPublishedProvidersForConsumerRequest, opts ...call.Option) (*ListPublishedProvidersForConsumerResponse, error) { - wireReq, err := listPublishedProvidersForConsumerRequestToWire(req) +func (c *internalClient) ListPublishedProvidersForConsumer(ctx context.Context, req ListPublishedProvidersForConsumerRequest, opts ...call.Option) (*ListPublishedProvidersForConsumerResponse, error) { + wireReq, err := listPublishedProvidersForConsumerRequestToWire(&req) if err != nil { return nil, err } @@ -1308,7 +1322,7 @@ func (c *internalClient) ListPublishedProvidersForConsumer(ctx context.Context, // // For example: // -// for item, err := range c.ListPublishedProvidersForConsumerIter(ctx, &ListPublishedProvidersForConsumerRequest{}) { +// for item, err := range c.ListPublishedProvidersForConsumerIter(ctx, ListPublishedProvidersForConsumerRequest{}) { // if err != nil { // return err // } @@ -1320,16 +1334,13 @@ func (c *internalClient) ListPublishedProvidersForConsumer(ctx context.Context, // // Callers who need custom pagination logic should use // ListPublishedProvidersForConsumer directly. -func (c *internalClient) ListPublishedProvidersForConsumerIter(ctx context.Context, req *ListPublishedProvidersForConsumerRequest, opts ...call.Option) iter.Seq2[*ProviderInfo, error] { +func (c *internalClient) ListPublishedProvidersForConsumerIter(ctx context.Context, req ListPublishedProvidersForConsumerRequest, opts ...call.Option) iter.Seq2[*ProviderInfo, error] { return func(yield func(*ProviderInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListPublishedProvidersForConsumerRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListPublishedProvidersForConsumer(ctx, &pageReq, opts...) + resp, err := c.ListPublishedProvidersForConsumer(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1350,8 +1361,8 @@ func (c *internalClient) ListPublishedProvidersForConsumerIter(ctx context.Conte // Search published listings in the Databricks Marketplace that the consumer has // access to. This query supports a variety of different search parameters and // performs fuzzy matching. -func (c *internalClient) SearchPublishedListingsForConsumer(ctx context.Context, req *SearchPublishedListingsForConsumerRequest, opts ...call.Option) (*SearchPublishedListingsForConsumerResponse, error) { - wireReq, err := searchPublishedListingsForConsumerRequestToWire(req) +func (c *internalClient) SearchPublishedListingsForConsumer(ctx context.Context, req SearchPublishedListingsForConsumerRequest, opts ...call.Option) (*SearchPublishedListingsForConsumerResponse, error) { + wireReq, err := searchPublishedListingsForConsumerRequestToWire(&req) if err != nil { return nil, err } @@ -1439,7 +1450,7 @@ func (c *internalClient) SearchPublishedListingsForConsumer(ctx context.Context, // // For example: // -// for item, err := range c.SearchPublishedListingsForConsumerIter(ctx, &SearchPublishedListingsForConsumerRequest{}) { +// for item, err := range c.SearchPublishedListingsForConsumerIter(ctx, SearchPublishedListingsForConsumerRequest{}) { // if err != nil { // return err // } @@ -1451,16 +1462,13 @@ func (c *internalClient) SearchPublishedListingsForConsumer(ctx context.Context, // // Callers who need custom pagination logic should use // SearchPublishedListingsForConsumer directly. -func (c *internalClient) SearchPublishedListingsForConsumerIter(ctx context.Context, req *SearchPublishedListingsForConsumerRequest, opts ...call.Option) iter.Seq2[*Listing, error] { +func (c *internalClient) SearchPublishedListingsForConsumerIter(ctx context.Context, req SearchPublishedListingsForConsumerRequest, opts ...call.Option) iter.Seq2[*Listing, error] { return func(yield func(*Listing, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := SearchPublishedListingsForConsumerRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.SearchPublishedListingsForConsumer(ctx, &pageReq, opts...) + resp, err := c.SearchPublishedListingsForConsumer(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1479,7 +1487,7 @@ func (c *internalClient) SearchPublishedListingsForConsumerIter(ctx context.Cont } // Uninstall an installation associated with a Databricks Marketplace listing. -func (c *internalClient) UninstallListing(ctx context.Context, req *DeleteInstallationRequest, opts ...call.Option) (*DeleteInstallationResponse, error) { +func (c *internalClient) UninstallListing(ctx context.Context, req DeleteInstallationRequest, opts ...call.Option) (*DeleteInstallationResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1493,9 +1501,17 @@ func (c *internalClient) UninstallListing(ctx context.Context, req *DeleteInstal } pb := pathBuilder{} pb.literal("/api/2.1/marketplace-consumer/listings/") - pb.singleSegment(*req.ListingId) + if req.ListingId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ListingId) + } pb.literal("/installations/") - pb.singleSegment(*req.InstallationId) + if req.InstallationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.InstallationId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1539,8 +1555,8 @@ func (c *internalClient) UninstallListing(ctx context.Context, req *DeleteInstal // the fields not included in the installation table 1. the token will be rotate // if the rotateToken flag is true 2. the token will be forcibly rotate if the // rotateToken flag is true and the tokenInfo field is empty -func (c *internalClient) UpdateInstallationDetail(ctx context.Context, req *UpdateInstallationRequest, opts ...call.Option) (*UpdateInstallationResponse, error) { - wireReq, err := updateInstallationRequestToWire(req) +func (c *internalClient) UpdateInstallationDetail(ctx context.Context, req UpdateInstallationRequest, opts ...call.Option) (*UpdateInstallationResponse, error) { + wireReq, err := updateInstallationRequestToWire(&req) if err != nil { return nil, err } @@ -1561,9 +1577,17 @@ func (c *internalClient) UpdateInstallationDetail(ctx context.Context, req *Upda } pb := pathBuilder{} pb.literal("/api/2.1/marketplace-consumer/listings/") - pb.singleSegment(*req.ListingId) + if req.ListingId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ListingId) + } pb.literal("/installations/") - pb.singleSegment(*req.InstallationId) + if req.InstallationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.InstallationId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1610,8 +1634,8 @@ func (c *internalClient) UpdateInstallationDetail(ctx context.Context, req *Upda } // Associate an exchange with a listing -func (c *internalClient) AddExchangeForListing(ctx context.Context, req *AddExchangeForListingRequest, opts ...call.Option) (*AddExchangeForListingResponse, error) { - wireReq, err := addExchangeForListingRequestToWire(req) +func (c *internalClient) AddExchangeForListing(ctx context.Context, req AddExchangeForListingRequest, opts ...call.Option) (*AddExchangeForListingResponse, error) { + wireReq, err := addExchangeForListingRequestToWire(&req) if err != nil { return nil, err } @@ -1676,8 +1700,8 @@ func (c *internalClient) AddExchangeForListing(ctx context.Context, req *AddExch } // Create an exchange -func (c *internalClient) CreateExchange(ctx context.Context, req *CreateExchangeRequest, opts ...call.Option) (*CreateExchangeResponse, error) { - wireReq, err := createExchangeRequestToWire(req) +func (c *internalClient) CreateExchange(ctx context.Context, req CreateExchangeRequest, opts ...call.Option) (*CreateExchangeResponse, error) { + wireReq, err := createExchangeRequestToWire(&req) if err != nil { return nil, err } @@ -1742,8 +1766,8 @@ func (c *internalClient) CreateExchange(ctx context.Context, req *CreateExchange } // Add an exchange filter. -func (c *internalClient) CreateExchangeFilter(ctx context.Context, req *CreateExchangeFilterRequest, opts ...call.Option) (*CreateExchangeFilterResponse, error) { - wireReq, err := createExchangeFilterRequestToWire(req) +func (c *internalClient) CreateExchangeFilter(ctx context.Context, req CreateExchangeFilterRequest, opts ...call.Option) (*CreateExchangeFilterResponse, error) { + wireReq, err := createExchangeFilterRequestToWire(&req) if err != nil { return nil, err } @@ -1809,8 +1833,8 @@ func (c *internalClient) CreateExchangeFilter(ctx context.Context, req *CreateEx // Create a file. Currently, only provider icons and attached notebooks are // supported. -func (c *internalClient) CreateFile(ctx context.Context, req *CreateFileRequest, opts ...call.Option) (*CreateFileResponse, error) { - wireReq, err := createFileRequestToWire(req) +func (c *internalClient) CreateFile(ctx context.Context, req CreateFileRequest, opts ...call.Option) (*CreateFileResponse, error) { + wireReq, err := createFileRequestToWire(&req) if err != nil { return nil, err } @@ -1875,8 +1899,8 @@ func (c *internalClient) CreateFile(ctx context.Context, req *CreateFileRequest, } // Create a new listing -func (c *internalClient) CreateListing(ctx context.Context, req *CreateListingRequest, opts ...call.Option) (*CreateListingResponse, error) { - wireReq, err := createListingRequestToWire(req) +func (c *internalClient) CreateListing(ctx context.Context, req CreateListingRequest, opts ...call.Option) (*CreateListingResponse, error) { + wireReq, err := createListingRequestToWire(&req) if err != nil { return nil, err } @@ -1941,8 +1965,8 @@ func (c *internalClient) CreateListing(ctx context.Context, req *CreateListingRe } // Create a provider -func (c *internalClient) CreateProvider(ctx context.Context, req *CreateProviderRequest, opts ...call.Option) (*CreateProviderResponse, error) { - wireReq, err := createProviderRequestToWire(req) +func (c *internalClient) CreateProvider(ctx context.Context, req CreateProviderRequest, opts ...call.Option) (*CreateProviderResponse, error) { + wireReq, err := createProviderRequestToWire(&req) if err != nil { return nil, err } @@ -2008,8 +2032,8 @@ func (c *internalClient) CreateProvider(ctx context.Context, req *CreateProvider // Create provider analytics dashboard. Returns Marketplace specific `id`. Not // to be confused with the Lakeview dashboard id. -func (c *internalClient) CreateProviderAnalyticsDashboard(ctx context.Context, req *CreateProviderAnalyticsDashboardRequest, opts ...call.Option) (*CreateProviderAnalyticsDashboardResponse, error) { - wireReq, err := createProviderAnalyticsDashboardRequestToWire(req) +func (c *internalClient) CreateProviderAnalyticsDashboard(ctx context.Context, req CreateProviderAnalyticsDashboardRequest, opts ...call.Option) (*CreateProviderAnalyticsDashboardResponse, error) { + wireReq, err := createProviderAnalyticsDashboardRequestToWire(&req) if err != nil { return nil, err } @@ -2074,7 +2098,7 @@ func (c *internalClient) CreateProviderAnalyticsDashboard(ctx context.Context, r } // This removes a listing from marketplace. -func (c *internalClient) DeleteExchange(ctx context.Context, req *DeleteExchangeRequest, opts ...call.Option) (*DeleteExchangeResponse, error) { +func (c *internalClient) DeleteExchange(ctx context.Context, req DeleteExchangeRequest, opts ...call.Option) (*DeleteExchangeResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2088,7 +2112,11 @@ func (c *internalClient) DeleteExchange(ctx context.Context, req *DeleteExchange } pb := pathBuilder{} pb.literal("/api/2.0/marketplace-exchange/exchanges/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2128,7 +2156,7 @@ func (c *internalClient) DeleteExchange(ctx context.Context, req *DeleteExchange } // Delete an exchange filter -func (c *internalClient) DeleteExchangeFilter(ctx context.Context, req *DeleteExchangeFilterRequest, opts ...call.Option) (*DeleteExchangeFilterResponse, error) { +func (c *internalClient) DeleteExchangeFilter(ctx context.Context, req DeleteExchangeFilterRequest, opts ...call.Option) (*DeleteExchangeFilterResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2142,7 +2170,11 @@ func (c *internalClient) DeleteExchangeFilter(ctx context.Context, req *DeleteEx } pb := pathBuilder{} pb.literal("/api/2.0/marketplace-exchange/filters/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2182,7 +2214,7 @@ func (c *internalClient) DeleteExchangeFilter(ctx context.Context, req *DeleteEx } // Delete a file -func (c *internalClient) DeleteFile(ctx context.Context, req *DeleteFileRequest, opts ...call.Option) (*DeleteFileResponse, error) { +func (c *internalClient) DeleteFile(ctx context.Context, req DeleteFileRequest, opts ...call.Option) (*DeleteFileResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2196,7 +2228,11 @@ func (c *internalClient) DeleteFile(ctx context.Context, req *DeleteFileRequest, } pb := pathBuilder{} pb.literal("/api/2.0/marketplace-provider/files/") - pb.singleSegment(*req.FileId) + if req.FileId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FileId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2236,7 +2272,7 @@ func (c *internalClient) DeleteFile(ctx context.Context, req *DeleteFileRequest, } // Delete a listing -func (c *internalClient) DeleteListing(ctx context.Context, req *DeleteListingRequest, opts ...call.Option) (*DeleteListingResponse, error) { +func (c *internalClient) DeleteListing(ctx context.Context, req DeleteListingRequest, opts ...call.Option) (*DeleteListingResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2250,7 +2286,11 @@ func (c *internalClient) DeleteListing(ctx context.Context, req *DeleteListingRe } pb := pathBuilder{} pb.literal("/api/2.0/marketplace-provider/listings/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2290,7 +2330,7 @@ func (c *internalClient) DeleteListing(ctx context.Context, req *DeleteListingRe } // Delete provider -func (c *internalClient) DeleteProvider(ctx context.Context, req *DeleteProviderRequest, opts ...call.Option) (*DeleteProviderResponse, error) { +func (c *internalClient) DeleteProvider(ctx context.Context, req DeleteProviderRequest, opts ...call.Option) (*DeleteProviderResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2304,7 +2344,11 @@ func (c *internalClient) DeleteProvider(ctx context.Context, req *DeleteProvider } pb := pathBuilder{} pb.literal("/api/2.0/marketplace-provider/providers/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2344,7 +2388,7 @@ func (c *internalClient) DeleteProvider(ctx context.Context, req *DeleteProvider } // Get an exchange. -func (c *internalClient) GetExchange(ctx context.Context, req *GetExchangeRequest, opts ...call.Option) (*GetExchangeResponse, error) { +func (c *internalClient) GetExchange(ctx context.Context, req GetExchangeRequest, opts ...call.Option) (*GetExchangeResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2358,7 +2402,11 @@ func (c *internalClient) GetExchange(ctx context.Context, req *GetExchangeReques } pb := pathBuilder{} pb.literal("/api/2.0/marketplace-exchange/exchanges/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2404,7 +2452,7 @@ func (c *internalClient) GetExchange(ctx context.Context, req *GetExchangeReques } // Get a file -func (c *internalClient) GetFile(ctx context.Context, req *GetFileRequest, opts ...call.Option) (*GetFileResponse, error) { +func (c *internalClient) GetFile(ctx context.Context, req GetFileRequest, opts ...call.Option) (*GetFileResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2418,7 +2466,11 @@ func (c *internalClient) GetFile(ctx context.Context, req *GetFileRequest, opts } pb := pathBuilder{} pb.literal("/api/2.0/marketplace-provider/files/") - pb.singleSegment(*req.FileId) + if req.FileId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FileId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2464,7 +2516,7 @@ func (c *internalClient) GetFile(ctx context.Context, req *GetFileRequest, opts } // Get latest version of provider analytics dashboard. -func (c *internalClient) GetLatestVersionProviderAnalyticsDashboard(ctx context.Context, req *GetLatestVersionProviderAnalyticsDashboardRequest, opts ...call.Option) (*GetLatestVersionProviderAnalyticsDashboardResponse, error) { +func (c *internalClient) GetLatestVersionProviderAnalyticsDashboard(ctx context.Context, req GetLatestVersionProviderAnalyticsDashboardRequest, opts ...call.Option) (*GetLatestVersionProviderAnalyticsDashboardResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2521,7 +2573,7 @@ func (c *internalClient) GetLatestVersionProviderAnalyticsDashboard(ctx context. } // Get a listing -func (c *internalClient) GetListing(ctx context.Context, req *GetListingRequest, opts ...call.Option) (*GetListingResponse, error) { +func (c *internalClient) GetListing(ctx context.Context, req GetListingRequest, opts ...call.Option) (*GetListingResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2535,7 +2587,11 @@ func (c *internalClient) GetListing(ctx context.Context, req *GetListingRequest, } pb := pathBuilder{} pb.literal("/api/2.0/marketplace-provider/listings/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2582,8 +2638,8 @@ func (c *internalClient) GetListing(ctx context.Context, req *GetListingRequest, // List personalization requests to this provider. This will return all // personalization requests, regardless of which listing they are for. -func (c *internalClient) GetPersonalizationRequestsForProvider(ctx context.Context, req *GetPersonalizationRequestsForProviderRequest, opts ...call.Option) (*GetPersonalizationRequestsForProviderResponse, error) { - wireReq, err := getPersonalizationRequestsForProviderRequestToWire(req) +func (c *internalClient) GetPersonalizationRequestsForProvider(ctx context.Context, req GetPersonalizationRequestsForProviderRequest, opts ...call.Option) (*GetPersonalizationRequestsForProviderResponse, error) { + wireReq, err := getPersonalizationRequestsForProviderRequestToWire(&req) if err != nil { return nil, err } @@ -2653,7 +2709,7 @@ func (c *internalClient) GetPersonalizationRequestsForProvider(ctx context.Conte // // For example: // -// for item, err := range c.GetPersonalizationRequestsForProviderIter(ctx, &GetPersonalizationRequestsForProviderRequest{}) { +// for item, err := range c.GetPersonalizationRequestsForProviderIter(ctx, GetPersonalizationRequestsForProviderRequest{}) { // if err != nil { // return err // } @@ -2665,16 +2721,13 @@ func (c *internalClient) GetPersonalizationRequestsForProvider(ctx context.Conte // // Callers who need custom pagination logic should use // GetPersonalizationRequestsForProvider directly. -func (c *internalClient) GetPersonalizationRequestsForProviderIter(ctx context.Context, req *GetPersonalizationRequestsForProviderRequest, opts ...call.Option) iter.Seq2[*PersonalizationRequest, error] { +func (c *internalClient) GetPersonalizationRequestsForProviderIter(ctx context.Context, req GetPersonalizationRequestsForProviderRequest, opts ...call.Option) iter.Seq2[*PersonalizationRequest, error] { return func(yield func(*PersonalizationRequest, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := GetPersonalizationRequestsForProviderRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.GetPersonalizationRequestsForProvider(ctx, &pageReq, opts...) + resp, err := c.GetPersonalizationRequestsForProvider(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -2693,7 +2746,7 @@ func (c *internalClient) GetPersonalizationRequestsForProviderIter(ctx context.C } // Get provider profile -func (c *internalClient) GetProvider(ctx context.Context, req *GetProviderRequest, opts ...call.Option) (*GetProviderResponse, error) { +func (c *internalClient) GetProvider(ctx context.Context, req GetProviderRequest, opts ...call.Option) (*GetProviderResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2707,7 +2760,11 @@ func (c *internalClient) GetProvider(ctx context.Context, req *GetProviderReques } pb := pathBuilder{} pb.literal("/api/2.0/marketplace-provider/providers/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2753,8 +2810,8 @@ func (c *internalClient) GetProvider(ctx context.Context, req *GetProviderReques } // List exchange filter -func (c *internalClient) ListExchangeFilters(ctx context.Context, req *ListExchangeFiltersRequest, opts ...call.Option) (*ListExchangeFiltersResponse, error) { - wireReq, err := listExchangeFiltersRequestToWire(req) +func (c *internalClient) ListExchangeFilters(ctx context.Context, req ListExchangeFiltersRequest, opts ...call.Option) (*ListExchangeFiltersResponse, error) { + wireReq, err := listExchangeFiltersRequestToWire(&req) if err != nil { return nil, err } @@ -2827,7 +2884,7 @@ func (c *internalClient) ListExchangeFilters(ctx context.Context, req *ListExcha // // For example: // -// for item, err := range c.ListExchangeFiltersIter(ctx, &ListExchangeFiltersRequest{}) { +// for item, err := range c.ListExchangeFiltersIter(ctx, ListExchangeFiltersRequest{}) { // if err != nil { // return err // } @@ -2839,16 +2896,13 @@ func (c *internalClient) ListExchangeFilters(ctx context.Context, req *ListExcha // // Callers who need custom pagination logic should use // ListExchangeFilters directly. -func (c *internalClient) ListExchangeFiltersIter(ctx context.Context, req *ListExchangeFiltersRequest, opts ...call.Option) iter.Seq2[*ExchangeFilter, error] { +func (c *internalClient) ListExchangeFiltersIter(ctx context.Context, req ListExchangeFiltersRequest, opts ...call.Option) iter.Seq2[*ExchangeFilter, error] { return func(yield func(*ExchangeFilter, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListExchangeFiltersRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListExchangeFilters(ctx, &pageReq, opts...) + resp, err := c.ListExchangeFilters(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -2867,8 +2921,8 @@ func (c *internalClient) ListExchangeFiltersIter(ctx context.Context, req *ListE } // List exchanges visible to provider -func (c *internalClient) ListExchanges(ctx context.Context, req *ListExchangesRequest, opts ...call.Option) (*ListExchangesResponse, error) { - wireReq, err := listExchangesRequestToWire(req) +func (c *internalClient) ListExchanges(ctx context.Context, req ListExchangesRequest, opts ...call.Option) (*ListExchangesResponse, error) { + wireReq, err := listExchangesRequestToWire(&req) if err != nil { return nil, err } @@ -2938,7 +2992,7 @@ func (c *internalClient) ListExchanges(ctx context.Context, req *ListExchangesRe // // For example: // -// for item, err := range c.ListExchangesIter(ctx, &ListExchangesRequest{}) { +// for item, err := range c.ListExchangesIter(ctx, ListExchangesRequest{}) { // if err != nil { // return err // } @@ -2950,16 +3004,13 @@ func (c *internalClient) ListExchanges(ctx context.Context, req *ListExchangesRe // // Callers who need custom pagination logic should use // ListExchanges directly. -func (c *internalClient) ListExchangesIter(ctx context.Context, req *ListExchangesRequest, opts ...call.Option) iter.Seq2[*Exchange, error] { +func (c *internalClient) ListExchangesIter(ctx context.Context, req ListExchangesRequest, opts ...call.Option) iter.Seq2[*Exchange, error] { return func(yield func(*Exchange, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListExchangesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListExchanges(ctx, &pageReq, opts...) + resp, err := c.ListExchanges(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -2978,8 +3029,8 @@ func (c *internalClient) ListExchangesIter(ctx context.Context, req *ListExchang } // List exchanges associated with a listing -func (c *internalClient) ListExchangesForListing(ctx context.Context, req *ListExchangesForListingRequest, opts ...call.Option) (*ListExchangesForListingResponse, error) { - wireReq, err := listExchangesForListingRequestToWire(req) +func (c *internalClient) ListExchangesForListing(ctx context.Context, req ListExchangesForListingRequest, opts ...call.Option) (*ListExchangesForListingResponse, error) { + wireReq, err := listExchangesForListingRequestToWire(&req) if err != nil { return nil, err } @@ -3052,7 +3103,7 @@ func (c *internalClient) ListExchangesForListing(ctx context.Context, req *ListE // // For example: // -// for item, err := range c.ListExchangesForListingIter(ctx, &ListExchangesForListingRequest{}) { +// for item, err := range c.ListExchangesForListingIter(ctx, ListExchangesForListingRequest{}) { // if err != nil { // return err // } @@ -3064,16 +3115,13 @@ func (c *internalClient) ListExchangesForListing(ctx context.Context, req *ListE // // Callers who need custom pagination logic should use // ListExchangesForListing directly. -func (c *internalClient) ListExchangesForListingIter(ctx context.Context, req *ListExchangesForListingRequest, opts ...call.Option) iter.Seq2[*ExchangeListing, error] { +func (c *internalClient) ListExchangesForListingIter(ctx context.Context, req ListExchangesForListingRequest, opts ...call.Option) iter.Seq2[*ExchangeListing, error] { return func(yield func(*ExchangeListing, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListExchangesForListingRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListExchangesForListing(ctx, &pageReq, opts...) + resp, err := c.ListExchangesForListing(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -3092,8 +3140,8 @@ func (c *internalClient) ListExchangesForListingIter(ctx context.Context, req *L } // List files attached to a parent entity. -func (c *internalClient) ListFiles(ctx context.Context, req *ListFilesRequest, opts ...call.Option) (*ListFilesResponse, error) { - wireReq, err := listFilesRequestToWire(req) +func (c *internalClient) ListFiles(ctx context.Context, req ListFilesRequest, opts ...call.Option) (*ListFilesResponse, error) { + wireReq, err := listFilesRequestToWire(&req) if err != nil { return nil, err } @@ -3166,7 +3214,7 @@ func (c *internalClient) ListFiles(ctx context.Context, req *ListFilesRequest, o // // For example: // -// for item, err := range c.ListFilesIter(ctx, &ListFilesRequest{}) { +// for item, err := range c.ListFilesIter(ctx, ListFilesRequest{}) { // if err != nil { // return err // } @@ -3178,16 +3226,13 @@ func (c *internalClient) ListFiles(ctx context.Context, req *ListFilesRequest, o // // Callers who need custom pagination logic should use // ListFiles directly. -func (c *internalClient) ListFilesIter(ctx context.Context, req *ListFilesRequest, opts ...call.Option) iter.Seq2[*FileInfo, error] { +func (c *internalClient) ListFilesIter(ctx context.Context, req ListFilesRequest, opts ...call.Option) iter.Seq2[*FileInfo, error] { return func(yield func(*FileInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListFilesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListFiles(ctx, &pageReq, opts...) + resp, err := c.ListFiles(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -3206,8 +3251,8 @@ func (c *internalClient) ListFilesIter(ctx context.Context, req *ListFilesReques } // List listings owned by this provider -func (c *internalClient) ListListings(ctx context.Context, req *ListListingsRequest, opts ...call.Option) (*GetListingsResponse, error) { - wireReq, err := listListingsRequestToWire(req) +func (c *internalClient) ListListings(ctx context.Context, req ListListingsRequest, opts ...call.Option) (*GetListingsResponse, error) { + wireReq, err := listListingsRequestToWire(&req) if err != nil { return nil, err } @@ -3277,7 +3322,7 @@ func (c *internalClient) ListListings(ctx context.Context, req *ListListingsRequ // // For example: // -// for item, err := range c.ListListingsIter(ctx, &ListListingsRequest{}) { +// for item, err := range c.ListListingsIter(ctx, ListListingsRequest{}) { // if err != nil { // return err // } @@ -3289,16 +3334,13 @@ func (c *internalClient) ListListings(ctx context.Context, req *ListListingsRequ // // Callers who need custom pagination logic should use // ListListings directly. -func (c *internalClient) ListListingsIter(ctx context.Context, req *ListListingsRequest, opts ...call.Option) iter.Seq2[*Listing, error] { +func (c *internalClient) ListListingsIter(ctx context.Context, req ListListingsRequest, opts ...call.Option) iter.Seq2[*Listing, error] { return func(yield func(*Listing, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListListingsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListListings(ctx, &pageReq, opts...) + resp, err := c.ListListings(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -3317,8 +3359,8 @@ func (c *internalClient) ListListingsIter(ctx context.Context, req *ListListings } // List listings associated with an exchange -func (c *internalClient) ListListingsForExchange(ctx context.Context, req *ListListingsForExchangeRequest, opts ...call.Option) (*ListListingsForExchangeResponse, error) { - wireReq, err := listListingsForExchangeRequestToWire(req) +func (c *internalClient) ListListingsForExchange(ctx context.Context, req ListListingsForExchangeRequest, opts ...call.Option) (*ListListingsForExchangeResponse, error) { + wireReq, err := listListingsForExchangeRequestToWire(&req) if err != nil { return nil, err } @@ -3391,7 +3433,7 @@ func (c *internalClient) ListListingsForExchange(ctx context.Context, req *ListL // // For example: // -// for item, err := range c.ListListingsForExchangeIter(ctx, &ListListingsForExchangeRequest{}) { +// for item, err := range c.ListListingsForExchangeIter(ctx, ListListingsForExchangeRequest{}) { // if err != nil { // return err // } @@ -3403,16 +3445,13 @@ func (c *internalClient) ListListingsForExchange(ctx context.Context, req *ListL // // Callers who need custom pagination logic should use // ListListingsForExchange directly. -func (c *internalClient) ListListingsForExchangeIter(ctx context.Context, req *ListListingsForExchangeRequest, opts ...call.Option) iter.Seq2[*ExchangeListing, error] { +func (c *internalClient) ListListingsForExchangeIter(ctx context.Context, req ListListingsForExchangeRequest, opts ...call.Option) iter.Seq2[*ExchangeListing, error] { return func(yield func(*ExchangeListing, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListListingsForExchangeRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListListingsForExchange(ctx, &pageReq, opts...) + resp, err := c.ListListingsForExchange(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -3431,7 +3470,7 @@ func (c *internalClient) ListListingsForExchangeIter(ctx context.Context, req *L } // Get provider analytics dashboard. -func (c *internalClient) ListProviderAnalyticsDashboard(ctx context.Context, req *ListProviderAnalyticsDashboardRequest, opts ...call.Option) (*ListProviderAnalyticsDashboardResponse, error) { +func (c *internalClient) ListProviderAnalyticsDashboard(ctx context.Context, req ListProviderAnalyticsDashboardRequest, opts ...call.Option) (*ListProviderAnalyticsDashboardResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -3488,8 +3527,8 @@ func (c *internalClient) ListProviderAnalyticsDashboard(ctx context.Context, req } // List provider profiles for account. -func (c *internalClient) ListProviders(ctx context.Context, req *ListProvidersRequest, opts ...call.Option) (*ListProvidersResponse, error) { - wireReq, err := listProvidersRequestToWire(req) +func (c *internalClient) ListProviders(ctx context.Context, req ListProvidersRequest, opts ...call.Option) (*ListProvidersResponse, error) { + wireReq, err := listProvidersRequestToWire(&req) if err != nil { return nil, err } @@ -3559,7 +3598,7 @@ func (c *internalClient) ListProviders(ctx context.Context, req *ListProvidersRe // // For example: // -// for item, err := range c.ListProvidersIter(ctx, &ListProvidersRequest{}) { +// for item, err := range c.ListProvidersIter(ctx, ListProvidersRequest{}) { // if err != nil { // return err // } @@ -3571,16 +3610,13 @@ func (c *internalClient) ListProviders(ctx context.Context, req *ListProvidersRe // // Callers who need custom pagination logic should use // ListProviders directly. -func (c *internalClient) ListProvidersIter(ctx context.Context, req *ListProvidersRequest, opts ...call.Option) iter.Seq2[*ProviderInfo, error] { +func (c *internalClient) ListProvidersIter(ctx context.Context, req ListProvidersRequest, opts ...call.Option) iter.Seq2[*ProviderInfo, error] { return func(yield func(*ProviderInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListProvidersRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListProviders(ctx, &pageReq, opts...) + resp, err := c.ListProviders(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -3599,7 +3635,7 @@ func (c *internalClient) ListProvidersIter(ctx context.Context, req *ListProvide } // Disassociate an exchange with a listing -func (c *internalClient) RemoveExchangeForListing(ctx context.Context, req *RemoveExchangeForListingRequest, opts ...call.Option) (*RemoveExchangeForListingResponse, error) { +func (c *internalClient) RemoveExchangeForListing(ctx context.Context, req RemoveExchangeForListingRequest, opts ...call.Option) (*RemoveExchangeForListingResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -3613,7 +3649,11 @@ func (c *internalClient) RemoveExchangeForListing(ctx context.Context, req *Remo } pb := pathBuilder{} pb.literal("/api/2.0/marketplace-exchange/exchanges-for-listing/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -3653,8 +3693,8 @@ func (c *internalClient) RemoveExchangeForListing(ctx context.Context, req *Remo } // Update an exchange -func (c *internalClient) UpdateExchange(ctx context.Context, req *UpdateExchangeRequest, opts ...call.Option) (*UpdateExchangeResponse, error) { - wireReq, err := updateExchangeRequestToWire(req) +func (c *internalClient) UpdateExchange(ctx context.Context, req UpdateExchangeRequest, opts ...call.Option) (*UpdateExchangeResponse, error) { + wireReq, err := updateExchangeRequestToWire(&req) if err != nil { return nil, err } @@ -3675,7 +3715,11 @@ func (c *internalClient) UpdateExchange(ctx context.Context, req *UpdateExchange } pb := pathBuilder{} pb.literal("/api/2.0/marketplace-exchange/exchanges/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -3722,8 +3766,8 @@ func (c *internalClient) UpdateExchange(ctx context.Context, req *UpdateExchange } // Update an exchange filter. -func (c *internalClient) UpdateExchangeFilter(ctx context.Context, req *UpdateExchangeFilterRequest, opts ...call.Option) (*UpdateExchangeFilterResponse, error) { - wireReq, err := updateExchangeFilterRequestToWire(req) +func (c *internalClient) UpdateExchangeFilter(ctx context.Context, req UpdateExchangeFilterRequest, opts ...call.Option) (*UpdateExchangeFilterResponse, error) { + wireReq, err := updateExchangeFilterRequestToWire(&req) if err != nil { return nil, err } @@ -3744,7 +3788,11 @@ func (c *internalClient) UpdateExchangeFilter(ctx context.Context, req *UpdateEx } pb := pathBuilder{} pb.literal("/api/2.0/marketplace-exchange/filters/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -3791,8 +3839,8 @@ func (c *internalClient) UpdateExchangeFilter(ctx context.Context, req *UpdateEx } // Update a listing -func (c *internalClient) UpdateListing(ctx context.Context, req *UpdateListingRequest, opts ...call.Option) (*UpdateListingResponse, error) { - wireReq, err := updateListingRequestToWire(req) +func (c *internalClient) UpdateListing(ctx context.Context, req UpdateListingRequest, opts ...call.Option) (*UpdateListingResponse, error) { + wireReq, err := updateListingRequestToWire(&req) if err != nil { return nil, err } @@ -3813,7 +3861,11 @@ func (c *internalClient) UpdateListing(ctx context.Context, req *UpdateListingRe } pb := pathBuilder{} pb.literal("/api/2.0/marketplace-provider/listings/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -3861,8 +3913,8 @@ func (c *internalClient) UpdateListing(ctx context.Context, req *UpdateListingRe // Update personalization request. This method only permits updating the status // of the request. -func (c *internalClient) UpdatePersonalizationRequestStatus(ctx context.Context, req *UpdatePersonalizationRequestStatusRequest, opts ...call.Option) (*UpdatePersonalizationRequestStatusResponse, error) { - wireReq, err := updatePersonalizationRequestStatusRequestToWire(req) +func (c *internalClient) UpdatePersonalizationRequestStatus(ctx context.Context, req UpdatePersonalizationRequestStatusRequest, opts ...call.Option) (*UpdatePersonalizationRequestStatusResponse, error) { + wireReq, err := updatePersonalizationRequestStatusRequestToWire(&req) if err != nil { return nil, err } @@ -3883,9 +3935,17 @@ func (c *internalClient) UpdatePersonalizationRequestStatus(ctx context.Context, } pb := pathBuilder{} pb.literal("/api/2.0/marketplace-provider/listings/") - pb.singleSegment(*req.ListingId) + if req.ListingId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ListingId) + } pb.literal("/personalization-requests/") - pb.singleSegment(*req.RequestId) + if req.RequestId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.RequestId) + } pb.literal("/request-status") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -3933,8 +3993,8 @@ func (c *internalClient) UpdatePersonalizationRequestStatus(ctx context.Context, } // Update provider profile -func (c *internalClient) UpdateProvider(ctx context.Context, req *UpdateProviderRequest, opts ...call.Option) (*UpdateProviderResponse, error) { - wireReq, err := updateProviderRequestToWire(req) +func (c *internalClient) UpdateProvider(ctx context.Context, req UpdateProviderRequest, opts ...call.Option) (*UpdateProviderResponse, error) { + wireReq, err := updateProviderRequestToWire(&req) if err != nil { return nil, err } @@ -3955,7 +4015,11 @@ func (c *internalClient) UpdateProvider(ctx context.Context, req *UpdateProvider } pb := pathBuilder{} pb.literal("/api/2.0/marketplace-provider/providers/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -4002,8 +4066,8 @@ func (c *internalClient) UpdateProvider(ctx context.Context, req *UpdateProvider } // Update provider analytics dashboard. -func (c *internalClient) UpdateProviderAnalyticsDashboard(ctx context.Context, req *UpdateProviderAnalyticsDashboardRequest, opts ...call.Option) (*UpdateProviderAnalyticsDashboardResponse, error) { - wireReq, err := updateProviderAnalyticsDashboardRequestToWire(req) +func (c *internalClient) UpdateProviderAnalyticsDashboard(ctx context.Context, req UpdateProviderAnalyticsDashboardRequest, opts ...call.Option) (*UpdateProviderAnalyticsDashboardResponse, error) { + wireReq, err := updateProviderAnalyticsDashboardRequestToWire(&req) if err != nil { return nil, err } @@ -4024,7 +4088,11 @@ func (c *internalClient) UpdateProviderAnalyticsDashboard(ctx context.Context, r } pb := pathBuilder{} pb.literal("/api/2.0/marketplace-provider/analytics_dashboard/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/marketplaces/v1/genhelper.go b/marketplaces/v1/genhelper.go old mode 100755 new mode 100644 index aa6797f..67d5ee8 --- a/marketplaces/v1/genhelper.go +++ b/marketplaces/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/marketplaces/v1/wire.go b/marketplaces/v1/wire.go old mode 100755 new mode 100644 index fa86c36..d6fcdf9 --- a/marketplaces/v1/wire.go +++ b/marketplaces/v1/wire.go @@ -3,9 +3,55 @@ package marketplaces import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type addExchangeForListingRequestWire struct { ListingId *string `json:"listing_id,omitempty"` ExchangeId *string `json:"exchange_id,omitempty"` @@ -410,7 +456,7 @@ func createProviderResponseFromWire(w *createProviderResponseWire) (*CreateProvi } type dataRefreshInfoWire struct { - Interval *int64 `json:"interval,omitempty"` + Interval *wireInt64 `json:"interval,omitempty"` Unit DataRefresh `json:"unit,omitempty"` } @@ -418,8 +464,12 @@ func dataRefreshInfoToWire(v *DataRefreshInfo) (*dataRefreshInfoWire, error) { if v == nil { return nil, nil } + intervalWireValue, err := int64ToWire(v.Interval) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DataRefreshInfo.Interval", err) + } return &dataRefreshInfoWire{ - Interval: v.Interval, + Interval: intervalWireValue, Unit: v.Unit, }, nil } @@ -428,8 +478,12 @@ func dataRefreshInfoFromWire(w *dataRefreshInfoWire) (*DataRefreshInfo, error) { if w == nil { return nil, nil } + intervalPublicValue, err := int64FromWire(w.Interval) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DataRefreshInfo.Interval", err) + } return &DataRefreshInfo{ - Interval: w.Interval, + Interval: intervalPublicValue, Unit: w.Unit, }, nil } @@ -439,9 +493,9 @@ type exchangeWire struct { Name *string `json:"name,omitempty"` Comment *string `json:"comment,omitempty"` Filters []exchangeFilterWire `json:"filters,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` LinkedListings []exchangeListingWire `json:"linked_listings,omitempty"` } @@ -454,6 +508,14 @@ func exchangeToWire(v *Exchange) (*exchangeWire, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "Exchange.Filters", err) } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Exchange.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Exchange.UpdatedAt", err) + } linkedListingsWireValue, err := convertSlice(v.LinkedListings, exchangeListingToWire) if err != nil { return nil, fmt.Errorf("%s: %w", "Exchange.LinkedListings", err) @@ -463,9 +525,9 @@ func exchangeToWire(v *Exchange) (*exchangeWire, error) { Name: v.Name, Comment: v.Comment, Filters: filtersWireValue, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, LinkedListings: linkedListingsWireValue, }, nil @@ -479,6 +541,14 @@ func exchangeFromWire(w *exchangeWire) (*Exchange, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "Exchange.Filters", err) } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Exchange.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Exchange.UpdatedAt", err) + } linkedListingsPublicValue, err := convertSlice(w.LinkedListings, exchangeListingFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "Exchange.LinkedListings", err) @@ -488,9 +558,9 @@ func exchangeFromWire(w *exchangeWire) (*Exchange, error) { Name: w.Name, Comment: w.Comment, Filters: filtersPublicValue, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, LinkedListings: linkedListingsPublicValue, }, nil @@ -501,9 +571,9 @@ type exchangeFilterWire struct { ExchangeId *string `json:"exchange_id,omitempty"` FilterValue *string `json:"filter_value,omitempty"` Name *string `json:"name,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` FilterType ExchangeFilterType `json:"filter_type,omitempty"` } @@ -512,14 +582,22 @@ func exchangeFilterToWire(v *ExchangeFilter) (*exchangeFilterWire, error) { if v == nil { return nil, nil } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ExchangeFilter.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ExchangeFilter.UpdatedAt", err) + } return &exchangeFilterWire{ Id: v.Id, ExchangeId: v.ExchangeId, FilterValue: v.FilterValue, Name: v.Name, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, FilterType: v.FilterType, }, nil @@ -529,40 +607,52 @@ func exchangeFilterFromWire(w *exchangeFilterWire) (*ExchangeFilter, error) { if w == nil { return nil, nil } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ExchangeFilter.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ExchangeFilter.UpdatedAt", err) + } return &ExchangeFilter{ Id: w.Id, ExchangeId: w.ExchangeId, FilterValue: w.FilterValue, Name: w.Name, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, FilterType: w.FilterType, }, nil } type exchangeListingWire struct { - Id *string `json:"id,omitempty"` - ExchangeId *string `json:"exchange_id,omitempty"` - ExchangeName *string `json:"exchange_name,omitempty"` - ListingId *string `json:"listing_id,omitempty"` - ListingName *string `json:"listing_name,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` - CreatedBy *string `json:"created_by,omitempty"` + Id *string `json:"id,omitempty"` + ExchangeId *string `json:"exchange_id,omitempty"` + ExchangeName *string `json:"exchange_name,omitempty"` + ListingId *string `json:"listing_id,omitempty"` + ListingName *string `json:"listing_name,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` + CreatedBy *string `json:"created_by,omitempty"` } func exchangeListingToWire(v *ExchangeListing) (*exchangeListingWire, error) { if v == nil { return nil, nil } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ExchangeListing.CreatedAt", err) + } return &exchangeListingWire{ Id: v.Id, ExchangeId: v.ExchangeId, ExchangeName: v.ExchangeName, ListingId: v.ListingId, ListingName: v.ListingName, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, }, nil } @@ -571,13 +661,17 @@ func exchangeListingFromWire(w *exchangeListingWire) (*ExchangeListing, error) { if w == nil { return nil, nil } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ExchangeListing.CreatedAt", err) + } return &ExchangeListing{ Id: w.Id, ExchangeId: w.ExchangeId, ExchangeName: w.ExchangeName, ListingId: w.ListingId, ListingName: w.ListingName, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, }, nil } @@ -588,8 +682,8 @@ type fileInfoWire struct { FileParent *fileParentWire `json:"file_parent,omitempty"` MimeType *string `json:"mime_type,omitempty"` DownloadLink *string `json:"download_link,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` DisplayName *string `json:"display_name,omitempty"` Status FileStatus `json:"status,omitempty"` StatusMessage *string `json:"status_message,omitempty"` @@ -603,14 +697,22 @@ func fileInfoToWire(v *FileInfo) (*fileInfoWire, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "FileInfo.FileParent", err) } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FileInfo.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FileInfo.UpdatedAt", err) + } return &fileInfoWire{ Id: v.Id, MarketplaceFileType: v.MarketplaceFileType, FileParent: fileParentWireValue, MimeType: v.MimeType, DownloadLink: v.DownloadLink, - CreatedAt: v.CreatedAt, - UpdatedAt: v.UpdatedAt, + CreatedAt: createdAtWireValue, + UpdatedAt: updatedAtWireValue, DisplayName: v.DisplayName, Status: v.Status, StatusMessage: v.StatusMessage, @@ -625,14 +727,22 @@ func fileInfoFromWire(w *fileInfoWire) (*FileInfo, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "FileInfo.FileParent", err) } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FileInfo.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FileInfo.UpdatedAt", err) + } return &FileInfo{ Id: w.Id, MarketplaceFileType: w.MarketplaceFileType, FileParent: fileParentPublicValue, MimeType: w.MimeType, DownloadLink: w.DownloadLink, - CreatedAt: w.CreatedAt, - UpdatedAt: w.UpdatedAt, + CreatedAt: createdAtPublicValue, + UpdatedAt: updatedAtPublicValue, DisplayName: w.DisplayName, Status: w.Status, StatusMessage: w.StatusMessage, @@ -735,15 +845,19 @@ func getInstallationDetailsRequestToWire(v *GetInstallationDetailsRequest) (*get } type getLatestVersionProviderAnalyticsDashboardResponseWire struct { - Version *int64 `json:"version,omitempty"` + Version *wireInt64 `json:"version,omitempty"` } func getLatestVersionProviderAnalyticsDashboardResponseFromWire(w *getLatestVersionProviderAnalyticsDashboardResponseWire) (*GetLatestVersionProviderAnalyticsDashboardResponse, error) { if w == nil { return nil, nil } + versionPublicValue, err := int64FromWire(w.Version) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetLatestVersionProviderAnalyticsDashboardResponse.Version", err) + } return &GetLatestVersionProviderAnalyticsDashboardResponse{ - Version: w.Version, + Version: versionPublicValue, }, nil } @@ -945,7 +1059,7 @@ type installationDetailWire struct { ListingId *string `json:"listing_id,omitempty"` ShareName *string `json:"share_name,omitempty"` CatalogName *string `json:"catalog_name,omitempty"` - InstalledOn *int64 `json:"installed_on,omitempty"` + InstalledOn *wireInt64 `json:"installed_on,omitempty"` Status InstallationStatus `json:"status,omitempty"` ErrorMessage *string `json:"error_message,omitempty"` ListingName *string `json:"listing_name,omitempty"` @@ -960,6 +1074,10 @@ func installationDetailToWire(v *InstallationDetail) (*installationDetailWire, e if v == nil { return nil, nil } + installedOnWireValue, err := int64ToWire(v.InstalledOn) + if err != nil { + return nil, fmt.Errorf("%s: %w", "InstallationDetail.InstalledOn", err) + } tokensWireValue, err := convertSlice(v.Tokens, tokenInfoToWire) if err != nil { return nil, fmt.Errorf("%s: %w", "InstallationDetail.Tokens", err) @@ -973,7 +1091,7 @@ func installationDetailToWire(v *InstallationDetail) (*installationDetailWire, e ListingId: v.ListingId, ShareName: v.ShareName, CatalogName: v.CatalogName, - InstalledOn: v.InstalledOn, + InstalledOn: installedOnWireValue, Status: v.Status, ErrorMessage: v.ErrorMessage, ListingName: v.ListingName, @@ -989,6 +1107,10 @@ func installationDetailFromWire(w *installationDetailWire) (*InstallationDetail, if w == nil { return nil, nil } + installedOnPublicValue, err := int64FromWire(w.InstalledOn) + if err != nil { + return nil, fmt.Errorf("%s: %w", "InstallationDetail.InstalledOn", err) + } tokensPublicValue, err := convertSlice(w.Tokens, tokenInfoFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "InstallationDetail.Tokens", err) @@ -1002,7 +1124,7 @@ func installationDetailFromWire(w *installationDetailWire) (*InstallationDetail, ListingId: w.ListingId, ShareName: w.ShareName, CatalogName: w.CatalogName, - InstalledOn: w.InstalledOn, + InstalledOn: installedOnPublicValue, Status: w.Status, ErrorMessage: w.ErrorMessage, ListingName: w.ListingName, @@ -1316,18 +1438,22 @@ func listPersonalizationRequestsForConsumerRequestToWire(v *ListPersonalizationR } type listProviderAnalyticsDashboardResponseWire struct { - Id *string `json:"id,omitempty"` - Version *int64 `json:"version,omitempty"` - DashboardId *string `json:"dashboard_id,omitempty"` + Id *string `json:"id,omitempty"` + Version *wireInt64 `json:"version,omitempty"` + DashboardId *string `json:"dashboard_id,omitempty"` } func listProviderAnalyticsDashboardResponseFromWire(w *listProviderAnalyticsDashboardResponseWire) (*ListProviderAnalyticsDashboardResponse, error) { if w == nil { return nil, nil } + versionPublicValue, err := int64FromWire(w.Version) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListProviderAnalyticsDashboardResponse.Version", err) + } return &ListProviderAnalyticsDashboardResponse{ Id: w.Id, - Version: w.Version, + Version: versionPublicValue, DashboardId: w.DashboardId, }, nil } @@ -1492,8 +1618,8 @@ type listingDetailWire struct { PricingModel *string `json:"pricing_model,omitempty"` UpdateFrequency *dataRefreshInfoWire `json:"update_frequency,omitempty"` CollectionGranularity *dataRefreshInfoWire `json:"collection_granularity,omitempty"` - CollectionDateStart *int64 `json:"collection_date_start,omitempty"` - CollectionDateEnd *int64 `json:"collection_date_end,omitempty"` + CollectionDateStart *wireInt64 `json:"collection_date_start,omitempty"` + CollectionDateEnd *wireInt64 `json:"collection_date_end,omitempty"` DataSource *string `json:"data_source,omitempty"` Size *float64 `json:"size,omitempty"` Assets []AssetType `json:"assets,omitempty"` @@ -1517,6 +1643,14 @@ func listingDetailToWire(v *ListingDetail) (*listingDetailWire, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "ListingDetail.CollectionGranularity", err) } + collectionDateStartWireValue, err := int64ToWire(v.CollectionDateStart) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListingDetail.CollectionDateStart", err) + } + collectionDateEndWireValue, err := int64ToWire(v.CollectionDateEnd) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListingDetail.CollectionDateEnd", err) + } tagsWireValue, err := convertSlice(v.Tags, listingTagToWire) if err != nil { return nil, fmt.Errorf("%s: %w", "ListingDetail.Tags", err) @@ -1534,8 +1668,8 @@ func listingDetailToWire(v *ListingDetail) (*listingDetailWire, error) { PricingModel: v.PricingModel, UpdateFrequency: updateFrequencyWireValue, CollectionGranularity: collectionGranularityWireValue, - CollectionDateStart: v.CollectionDateStart, - CollectionDateEnd: v.CollectionDateEnd, + CollectionDateStart: collectionDateStartWireValue, + CollectionDateEnd: collectionDateEndWireValue, DataSource: v.DataSource, Size: v.Size, Assets: v.Assets, @@ -1560,6 +1694,14 @@ func listingDetailFromWire(w *listingDetailWire) (*ListingDetail, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "ListingDetail.CollectionGranularity", err) } + collectionDateStartPublicValue, err := int64FromWire(w.CollectionDateStart) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListingDetail.CollectionDateStart", err) + } + collectionDateEndPublicValue, err := int64FromWire(w.CollectionDateEnd) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListingDetail.CollectionDateEnd", err) + } tagsPublicValue, err := convertSlice(w.Tags, listingTagFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "ListingDetail.Tags", err) @@ -1577,8 +1719,8 @@ func listingDetailFromWire(w *listingDetailWire) (*ListingDetail, error) { PricingModel: w.PricingModel, UpdateFrequency: updateFrequencyPublicValue, CollectionGranularity: collectionGranularityPublicValue, - CollectionDateStart: w.CollectionDateStart, - CollectionDateEnd: w.CollectionDateEnd, + CollectionDateStart: collectionDateStartPublicValue, + CollectionDateEnd: collectionDateEndPublicValue, DataSource: w.DataSource, Size: w.Size, Assets: w.Assets, @@ -1645,16 +1787,16 @@ type listingSummaryWire struct { Share *shareInfoWire `json:"share,omitempty"` ProviderRegion *regionInfoWire `json:"provider_region,omitempty"` Setting *listingSettingWire `json:"setting,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` - PublishedAt *int64 `json:"published_at,omitempty"` + PublishedAt *wireInt64 `json:"published_at,omitempty"` PublishedBy *string `json:"published_by,omitempty"` Categories []Category `json:"categories,omitempty"` ListingType ListingType `json:"listingType,omitempty"` - CreatedById *int64 `json:"created_by_id,omitempty"` - UpdatedById *int64 `json:"updated_by_id,omitempty"` + CreatedById *wireInt64 `json:"created_by_id,omitempty"` + UpdatedById *wireInt64 `json:"updated_by_id,omitempty"` ProviderId *string `json:"provider_id,omitempty"` ExchangeIds []string `json:"exchange_ids,omitempty"` GitRepo *repoInfoWire `json:"git_repo,omitempty"` @@ -1676,6 +1818,26 @@ func listingSummaryToWire(v *ListingSummary) (*listingSummaryWire, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "ListingSummary.Setting", err) } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListingSummary.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListingSummary.UpdatedAt", err) + } + publishedAtWireValue, err := int64ToWire(v.PublishedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListingSummary.PublishedAt", err) + } + createdByIdWireValue, err := int64ToWire(v.CreatedById) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListingSummary.CreatedById", err) + } + updatedByIdWireValue, err := int64ToWire(v.UpdatedById) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListingSummary.UpdatedById", err) + } gitRepoWireValue, err := repoInfoToWire(v.GitRepo) if err != nil { return nil, fmt.Errorf("%s: %w", "ListingSummary.GitRepo", err) @@ -1687,16 +1849,16 @@ func listingSummaryToWire(v *ListingSummary) (*listingSummaryWire, error) { Share: shareWireValue, ProviderRegion: providerRegionWireValue, Setting: settingWireValue, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, - PublishedAt: v.PublishedAt, + PublishedAt: publishedAtWireValue, PublishedBy: v.PublishedBy, Categories: v.Categories, ListingType: v.ListingType, - CreatedById: v.CreatedById, - UpdatedById: v.UpdatedById, + CreatedById: createdByIdWireValue, + UpdatedById: updatedByIdWireValue, ProviderId: v.ProviderId, ExchangeIds: v.ExchangeIds, GitRepo: gitRepoWireValue, @@ -1719,6 +1881,26 @@ func listingSummaryFromWire(w *listingSummaryWire) (*ListingSummary, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "ListingSummary.Setting", err) } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListingSummary.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListingSummary.UpdatedAt", err) + } + publishedAtPublicValue, err := int64FromWire(w.PublishedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListingSummary.PublishedAt", err) + } + createdByIdPublicValue, err := int64FromWire(w.CreatedById) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListingSummary.CreatedById", err) + } + updatedByIdPublicValue, err := int64FromWire(w.UpdatedById) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListingSummary.UpdatedById", err) + } gitRepoPublicValue, err := repoInfoFromWire(w.GitRepo) if err != nil { return nil, fmt.Errorf("%s: %w", "ListingSummary.GitRepo", err) @@ -1730,16 +1912,16 @@ func listingSummaryFromWire(w *listingSummaryWire) (*ListingSummary, error) { Share: sharePublicValue, ProviderRegion: providerRegionPublicValue, Setting: settingPublicValue, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, - PublishedAt: w.PublishedAt, + PublishedAt: publishedAtPublicValue, PublishedBy: w.PublishedBy, Categories: w.Categories, ListingType: w.ListingType, - CreatedById: w.CreatedById, - UpdatedById: w.UpdatedById, + CreatedById: createdByIdPublicValue, + UpdatedById: updatedByIdPublicValue, ProviderId: w.ProviderId, ExchangeIds: w.ExchangeIds, GitRepo: gitRepoPublicValue, @@ -1780,9 +1962,9 @@ type personalizationRequestWire struct { Status PersonalizationRequestStatus `json:"status,omitempty"` StatusMessage *string `json:"status_message,omitempty"` Share *shareInfoWire `json:"share,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` ListingId *string `json:"listing_id,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` ListingName *string `json:"listing_name,omitempty"` IsFromLighthouse *bool `json:"is_from_lighthouse,omitempty"` @@ -1806,6 +1988,14 @@ func personalizationRequestFromWire(w *personalizationRequestWire) (*Personaliza if err != nil { return nil, fmt.Errorf("%s: %w", "PersonalizationRequest.Share", err) } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PersonalizationRequest.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PersonalizationRequest.UpdatedAt", err) + } return &PersonalizationRequest{ Id: w.Id, ConsumerRegion: consumerRegionPublicValue, @@ -1815,9 +2005,9 @@ func personalizationRequestFromWire(w *personalizationRequestWire) (*Personaliza Status: w.Status, StatusMessage: w.StatusMessage, Share: sharePublicValue, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, ListingId: w.ListingId, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, MetastoreId: w.MetastoreId, ListingName: w.ListingName, IsFromLighthouse: w.IsFromLighthouse, @@ -2067,26 +2257,38 @@ func tokenDetailFromWire(w *tokenDetailWire) (*TokenDetail, error) { } type tokenInfoWire struct { - Id *string `json:"id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` - CreatedBy *string `json:"created_by,omitempty"` - ActivationUrl *string `json:"activation_url,omitempty"` - ExpirationTime *int64 `json:"expiration_time,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` - UpdatedBy *string `json:"updated_by,omitempty"` + Id *string `json:"id,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` + CreatedBy *string `json:"created_by,omitempty"` + ActivationUrl *string `json:"activation_url,omitempty"` + ExpirationTime *wireInt64 `json:"expiration_time,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` + UpdatedBy *string `json:"updated_by,omitempty"` } func tokenInfoToWire(v *TokenInfo) (*tokenInfoWire, error) { if v == nil { return nil, nil } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TokenInfo.CreatedAt", err) + } + expirationTimeWireValue, err := int64ToWire(v.ExpirationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TokenInfo.ExpirationTime", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TokenInfo.UpdatedAt", err) + } return &tokenInfoWire{ Id: v.Id, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, ActivationUrl: v.ActivationUrl, - ExpirationTime: v.ExpirationTime, - UpdatedAt: v.UpdatedAt, + ExpirationTime: expirationTimeWireValue, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, }, nil } @@ -2095,13 +2297,25 @@ func tokenInfoFromWire(w *tokenInfoWire) (*TokenInfo, error) { if w == nil { return nil, nil } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TokenInfo.CreatedAt", err) + } + expirationTimePublicValue, err := int64FromWire(w.ExpirationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TokenInfo.ExpirationTime", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TokenInfo.UpdatedAt", err) + } return &TokenInfo{ Id: w.Id, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, ActivationUrl: w.ActivationUrl, - ExpirationTime: w.ExpirationTime, - UpdatedAt: w.UpdatedAt, + ExpirationTime: expirationTimePublicValue, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, }, nil } @@ -2297,33 +2511,41 @@ func updatePersonalizationRequestStatusResponseFromWire(w *updatePersonalization } type updateProviderAnalyticsDashboardRequestWire struct { - Id *string `json:"id,omitempty"` - Version *int64 `json:"version,omitempty"` + Id *string `json:"id,omitempty"` + Version *wireInt64 `json:"version,omitempty"` } func updateProviderAnalyticsDashboardRequestToWire(v *UpdateProviderAnalyticsDashboardRequest) (*updateProviderAnalyticsDashboardRequestWire, error) { if v == nil { return nil, nil } + versionWireValue, err := int64ToWire(v.Version) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateProviderAnalyticsDashboardRequest.Version", err) + } return &updateProviderAnalyticsDashboardRequestWire{ Id: v.Id, - Version: v.Version, + Version: versionWireValue, }, nil } type updateProviderAnalyticsDashboardResponseWire struct { - Id *string `json:"id,omitempty"` - Version *int64 `json:"version,omitempty"` - DashboardId *string `json:"dashboard_id,omitempty"` + Id *string `json:"id,omitempty"` + Version *wireInt64 `json:"version,omitempty"` + DashboardId *string `json:"dashboard_id,omitempty"` } func updateProviderAnalyticsDashboardResponseFromWire(w *updateProviderAnalyticsDashboardResponseWire) (*UpdateProviderAnalyticsDashboardResponse, error) { if w == nil { return nil, nil } + versionPublicValue, err := int64FromWire(w.Version) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateProviderAnalyticsDashboardResponse.Version", err) + } return &UpdateProviderAnalyticsDashboardResponse{ Id: w.Id, - Version: w.Version, + Version: versionPublicValue, DashboardId: w.DashboardId, }, nil } diff --git a/modelregistry/CHANGELOG.md b/modelregistry/CHANGELOG.md index 6224c04..19f237c 100644 --- a/modelregistry/CHANGELOG.md +++ b/modelregistry/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/modelregistry/go.mod b/modelregistry/go.mod index 00a624f..cab8e38 100644 --- a/modelregistry/go.mod +++ b/modelregistry/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/modelregistry/internal/version.go b/modelregistry/internal/version.go index 2e3e93e..8796168 100644 --- a/modelregistry/internal/version.go +++ b/modelregistry/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-modelregistry" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/modelregistry/v1/client.go b/modelregistry/v1/client.go old mode 100755 new mode 100644 index ccf7960..6dc1e37 --- a/modelregistry/v1/client.go +++ b/modelregistry/v1/client.go @@ -75,8 +75,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Approves a model version stage transition request. -func (c *internalClient) ApproveTransitionRequest(ctx context.Context, req *ApproveTransitionRequest, opts ...call.Option) (*ApproveTransitionResponse, error) { - wireReq, err := approveTransitionRequestToWire(req) +func (c *internalClient) ApproveTransitionRequest(ctx context.Context, req ApproveTransitionRequest, opts ...call.Option) (*ApproveTransitionResponse, error) { + wireReq, err := approveTransitionRequestToWire(&req) if err != nil { return nil, err } @@ -143,8 +143,8 @@ func (c *internalClient) ApproveTransitionRequest(ctx context.Context, req *Appr // Posts a comment on a model version. A comment can be submitted either by a // user or programmatically to display relevant information about the model. For // example, test results or deployment errors. -func (c *internalClient) CreateComment(ctx context.Context, req *CreateCommentRequest, opts ...call.Option) (*CreateCommentResponse, error) { - wireReq, err := createCommentRequestToWire(req) +func (c *internalClient) CreateComment(ctx context.Context, req CreateCommentRequest, opts ...call.Option) (*CreateCommentResponse, error) { + wireReq, err := createCommentRequestToWire(&req) if err != nil { return nil, err } @@ -209,8 +209,8 @@ func (c *internalClient) CreateComment(ctx context.Context, req *CreateCommentRe } // **NOTE:** This endpoint is in Public Preview. Creates a registry webhook. -func (c *internalClient) CreateRegistryWebhook(ctx context.Context, req *CreateRegistryWebhookRequest, opts ...call.Option) (*CreateRegistryWebhookResponse, error) { - wireReq, err := createRegistryWebhookRequestToWire(req) +func (c *internalClient) CreateRegistryWebhook(ctx context.Context, req CreateRegistryWebhookRequest, opts ...call.Option) (*CreateRegistryWebhookResponse, error) { + wireReq, err := createRegistryWebhookRequestToWire(&req) if err != nil { return nil, err } @@ -275,8 +275,8 @@ func (c *internalClient) CreateRegistryWebhook(ctx context.Context, req *CreateR } // Creates a model version stage transition request. -func (c *internalClient) CreateTransitionRequest(ctx context.Context, req *CreateTransitionRequest, opts ...call.Option) (*CreateTransitionResponse, error) { - wireReq, err := createTransitionRequestToWire(req) +func (c *internalClient) CreateTransitionRequest(ctx context.Context, req CreateTransitionRequest, opts ...call.Option) (*CreateTransitionResponse, error) { + wireReq, err := createTransitionRequestToWire(&req) if err != nil { return nil, err } @@ -341,8 +341,8 @@ func (c *internalClient) CreateTransitionRequest(ctx context.Context, req *Creat } // Deletes a comment on a model version. -func (c *internalClient) DeleteComment(ctx context.Context, req *DeleteCommentRequest, opts ...call.Option) (*DeleteCommentResponse, error) { - wireReq, err := deleteCommentRequestToWire(req) +func (c *internalClient) DeleteComment(ctx context.Context, req DeleteCommentRequest, opts ...call.Option) (*DeleteCommentResponse, error) { + wireReq, err := deleteCommentRequestToWire(&req) if err != nil { return nil, err } @@ -399,8 +399,8 @@ func (c *internalClient) DeleteComment(ctx context.Context, req *DeleteCommentRe } // **NOTE:** This endpoint is in Public Preview. Deletes a registry webhook. -func (c *internalClient) DeleteRegistryWebhook(ctx context.Context, req *DeleteRegistryWebhookRequest, opts ...call.Option) (*DeleteRegistryWebhookResponse, error) { - wireReq, err := deleteRegistryWebhookRequestToWire(req) +func (c *internalClient) DeleteRegistryWebhook(ctx context.Context, req DeleteRegistryWebhookRequest, opts ...call.Option) (*DeleteRegistryWebhookResponse, error) { + wireReq, err := deleteRegistryWebhookRequestToWire(&req) if err != nil { return nil, err } @@ -457,8 +457,8 @@ func (c *internalClient) DeleteRegistryWebhook(ctx context.Context, req *DeleteR } // Cancels a model version stage transition request. -func (c *internalClient) DeleteTransitionRequest(ctx context.Context, req *DeleteTransitionRequest, opts ...call.Option) (*DeleteTransitionResponse, error) { - wireReq, err := deleteTransitionRequestToWire(req) +func (c *internalClient) DeleteTransitionRequest(ctx context.Context, req DeleteTransitionRequest, opts ...call.Option) (*DeleteTransitionResponse, error) { + wireReq, err := deleteTransitionRequestToWire(&req) if err != nil { return nil, err } @@ -537,8 +537,8 @@ func (c *internalClient) DeleteTransitionRequest(ctx context.Context, req *Delet // the permission level of the requesting user on the model. // // [MLflow endpoint]: https://www.mlflow.org/docs/latest/rest-api.html#get-registeredmodel -func (c *internalClient) GetRegisteredModelDatabricks(ctx context.Context, req *GetRegisteredModelDatabricksRequest, opts ...call.Option) (*GetRegisteredModelDatabricksResponse, error) { - wireReq, err := getRegisteredModelDatabricksRequestToWire(req) +func (c *internalClient) GetRegisteredModelDatabricks(ctx context.Context, req GetRegisteredModelDatabricksRequest, opts ...call.Option) (*GetRegisteredModelDatabricksResponse, error) { + wireReq, err := getRegisteredModelDatabricksRequestToWire(&req) if err != nil { return nil, err } @@ -601,8 +601,8 @@ func (c *internalClient) GetRegisteredModelDatabricks(ctx context.Context, req * } // **NOTE:** This endpoint is in Public Preview. Lists all registry webhooks. -func (c *internalClient) ListRegistryWebhooks(ctx context.Context, req *ListRegistryWebhooksRequest, opts ...call.Option) (*ListRegistryWebhooksResponse, error) { - wireReq, err := listRegistryWebhooksRequestToWire(req) +func (c *internalClient) ListRegistryWebhooks(ctx context.Context, req ListRegistryWebhooksRequest, opts ...call.Option) (*ListRegistryWebhooksResponse, error) { + wireReq, err := listRegistryWebhooksRequestToWire(&req) if err != nil { return nil, err } @@ -678,7 +678,7 @@ func (c *internalClient) ListRegistryWebhooks(ctx context.Context, req *ListRegi // // For example: // -// for item, err := range c.ListRegistryWebhooksIter(ctx, &ListRegistryWebhooksRequest{}) { +// for item, err := range c.ListRegistryWebhooksIter(ctx, ListRegistryWebhooksRequest{}) { // if err != nil { // return err // } @@ -690,16 +690,13 @@ func (c *internalClient) ListRegistryWebhooks(ctx context.Context, req *ListRegi // // Callers who need custom pagination logic should use // ListRegistryWebhooks directly. -func (c *internalClient) ListRegistryWebhooksIter(ctx context.Context, req *ListRegistryWebhooksRequest, opts ...call.Option) iter.Seq2[*RegistryWebhook, error] { +func (c *internalClient) ListRegistryWebhooksIter(ctx context.Context, req ListRegistryWebhooksRequest, opts ...call.Option) iter.Seq2[*RegistryWebhook, error] { return func(yield func(*RegistryWebhook, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListRegistryWebhooksRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListRegistryWebhooks(ctx, &pageReq, opts...) + resp, err := c.ListRegistryWebhooks(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -718,8 +715,8 @@ func (c *internalClient) ListRegistryWebhooksIter(ctx context.Context, req *List } // Gets a list of all open stage transition requests for the model version. -func (c *internalClient) ListTransitionRequests(ctx context.Context, req *ListTransitionRequest, opts ...call.Option) (*ListTransitionResponse, error) { - wireReq, err := listTransitionRequestToWire(req) +func (c *internalClient) ListTransitionRequests(ctx context.Context, req ListTransitionRequest, opts ...call.Option) (*ListTransitionResponse, error) { + wireReq, err := listTransitionRequestToWire(&req) if err != nil { return nil, err } @@ -785,8 +782,8 @@ func (c *internalClient) ListTransitionRequests(ctx context.Context, req *ListTr } // Rejects a model version stage transition request. -func (c *internalClient) RejectTransitionRequest(ctx context.Context, req *RejectTransitionRequest, opts ...call.Option) (*RejectTransitionResponse, error) { - wireReq, err := rejectTransitionRequestToWire(req) +func (c *internalClient) RejectTransitionRequest(ctx context.Context, req RejectTransitionRequest, opts ...call.Option) (*RejectTransitionResponse, error) { + wireReq, err := rejectTransitionRequestToWire(&req) if err != nil { return nil, err } @@ -851,8 +848,8 @@ func (c *internalClient) RejectTransitionRequest(ctx context.Context, req *Rejec } // **NOTE:** This endpoint is in Public Preview. Tests a registry webhook. -func (c *internalClient) TestRegistryWebhook(ctx context.Context, req *TestRegistryWebhookRequest, opts ...call.Option) (*TestRegistryWebhookResponse, error) { - wireReq, err := testRegistryWebhookRequestToWire(req) +func (c *internalClient) TestRegistryWebhook(ctx context.Context, req TestRegistryWebhookRequest, opts ...call.Option) (*TestRegistryWebhookResponse, error) { + wireReq, err := testRegistryWebhookRequestToWire(&req) if err != nil { return nil, err } @@ -921,8 +918,8 @@ func (c *internalClient) TestRegistryWebhook(ctx context.Context, req *TestRegis // transition to be recorded. // // [MLflow endpoint]: https://www.mlflow.org/docs/latest/rest-api.html#transition-modelversion-stage -func (c *internalClient) TransitionModelVersionStageDatabricks(ctx context.Context, req *TransitionModelVersionStageDatabricksRequest, opts ...call.Option) (*TransitionModelVersionStageDatabricksResponse, error) { - wireReq, err := transitionModelVersionStageDatabricksRequestToWire(req) +func (c *internalClient) TransitionModelVersionStageDatabricks(ctx context.Context, req TransitionModelVersionStageDatabricksRequest, opts ...call.Option) (*TransitionModelVersionStageDatabricksResponse, error) { + wireReq, err := transitionModelVersionStageDatabricksRequestToWire(&req) if err != nil { return nil, err } @@ -987,8 +984,8 @@ func (c *internalClient) TransitionModelVersionStageDatabricks(ctx context.Conte } // Post an edit to a comment on a model version. -func (c *internalClient) UpdateComment(ctx context.Context, req *UpdateCommentRequest, opts ...call.Option) (*UpdateCommentResponse, error) { - wireReq, err := updateCommentRequestToWire(req) +func (c *internalClient) UpdateComment(ctx context.Context, req UpdateCommentRequest, opts ...call.Option) (*UpdateCommentResponse, error) { + wireReq, err := updateCommentRequestToWire(&req) if err != nil { return nil, err } @@ -1053,8 +1050,8 @@ func (c *internalClient) UpdateComment(ctx context.Context, req *UpdateCommentRe } // **NOTE:** This endpoint is in Public Preview. Updates a registry webhook. -func (c *internalClient) UpdateRegistryWebhook(ctx context.Context, req *UpdateRegistryWebhookRequest, opts ...call.Option) (*UpdateRegistryWebhookResponse, error) { - wireReq, err := updateRegistryWebhookRequestToWire(req) +func (c *internalClient) UpdateRegistryWebhook(ctx context.Context, req UpdateRegistryWebhookRequest, opts ...call.Option) (*UpdateRegistryWebhookResponse, error) { + wireReq, err := updateRegistryWebhookRequestToWire(&req) if err != nil { return nil, err } @@ -1119,8 +1116,8 @@ func (c *internalClient) UpdateRegistryWebhook(ctx context.Context, req *UpdateR } // Creates a model version. -func (c *internalClient) CreateModelVersion(ctx context.Context, req *CreateModelVersionRequest, opts ...call.Option) (*CreateModelVersionResponse, error) { - wireReq, err := createModelVersionRequestToWire(req) +func (c *internalClient) CreateModelVersion(ctx context.Context, req CreateModelVersionRequest, opts ...call.Option) (*CreateModelVersionResponse, error) { + wireReq, err := createModelVersionRequestToWire(&req) if err != nil { return nil, err } @@ -1187,8 +1184,8 @@ func (c *internalClient) CreateModelVersion(ctx context.Context, req *CreateMode // Creates a new registered model with the name specified in the request body. // Throws `RESOURCE_ALREADY_EXISTS` if a registered model with the given name // exists. -func (c *internalClient) CreateRegisteredModel(ctx context.Context, req *CreateRegisteredModelRequest, opts ...call.Option) (*CreateRegisteredModelResponse, error) { - wireReq, err := createRegisteredModelRequestToWire(req) +func (c *internalClient) CreateRegisteredModel(ctx context.Context, req CreateRegisteredModelRequest, opts ...call.Option) (*CreateRegisteredModelResponse, error) { + wireReq, err := createRegisteredModelRequestToWire(&req) if err != nil { return nil, err } @@ -1253,8 +1250,8 @@ func (c *internalClient) CreateRegisteredModel(ctx context.Context, req *CreateR } // Deletes a model version. -func (c *internalClient) DeleteModelVersion(ctx context.Context, req *DeleteModelVersionRequest, opts ...call.Option) (*DeleteModelVersionResponse, error) { - wireReq, err := deleteModelVersionRequestToWire(req) +func (c *internalClient) DeleteModelVersion(ctx context.Context, req DeleteModelVersionRequest, opts ...call.Option) (*DeleteModelVersionResponse, error) { + wireReq, err := deleteModelVersionRequestToWire(&req) if err != nil { return nil, err } @@ -1314,8 +1311,8 @@ func (c *internalClient) DeleteModelVersion(ctx context.Context, req *DeleteMode } // Deletes a model version tag. -func (c *internalClient) DeleteModelVersionTag(ctx context.Context, req *DeleteModelVersionTagRequest, opts ...call.Option) (*DeleteModelVersionTagResponse, error) { - wireReq, err := deleteModelVersionTagRequestToWire(req) +func (c *internalClient) DeleteModelVersionTag(ctx context.Context, req DeleteModelVersionTagRequest, opts ...call.Option) (*DeleteModelVersionTagResponse, error) { + wireReq, err := deleteModelVersionTagRequestToWire(&req) if err != nil { return nil, err } @@ -1378,8 +1375,8 @@ func (c *internalClient) DeleteModelVersionTag(ctx context.Context, req *DeleteM } // Deletes a registered model. -func (c *internalClient) DeleteRegisteredModel(ctx context.Context, req *DeleteRegisteredModelRequest, opts ...call.Option) (*DeleteRegisteredModelResponse, error) { - wireReq, err := deleteRegisteredModelRequestToWire(req) +func (c *internalClient) DeleteRegisteredModel(ctx context.Context, req DeleteRegisteredModelRequest, opts ...call.Option) (*DeleteRegisteredModelResponse, error) { + wireReq, err := deleteRegisteredModelRequestToWire(&req) if err != nil { return nil, err } @@ -1436,8 +1433,8 @@ func (c *internalClient) DeleteRegisteredModel(ctx context.Context, req *DeleteR } // Deletes the tag for a registered model. -func (c *internalClient) DeleteRegisteredModelTag(ctx context.Context, req *DeleteRegisteredModelTagRequest, opts ...call.Option) (*DeleteRegisteredModelTagResponse, error) { - wireReq, err := deleteRegisteredModelTagRequestToWire(req) +func (c *internalClient) DeleteRegisteredModelTag(ctx context.Context, req DeleteRegisteredModelTagRequest, opts ...call.Option) (*DeleteRegisteredModelTagResponse, error) { + wireReq, err := deleteRegisteredModelTagRequestToWire(&req) if err != nil { return nil, err } @@ -1497,8 +1494,8 @@ func (c *internalClient) DeleteRegisteredModelTag(ctx context.Context, req *Dele } // Get a model version. -func (c *internalClient) GetModelVersion(ctx context.Context, req *GetModelVersionRequest, opts ...call.Option) (*GetModelVersionResponse, error) { - wireReq, err := getModelVersionRequestToWire(req) +func (c *internalClient) GetModelVersion(ctx context.Context, req GetModelVersionRequest, opts ...call.Option) (*GetModelVersionResponse, error) { + wireReq, err := getModelVersionRequestToWire(&req) if err != nil { return nil, err } @@ -1564,8 +1561,8 @@ func (c *internalClient) GetModelVersion(ctx context.Context, req *GetModelVersi } // Gets a URI to download the model version. -func (c *internalClient) GetModelVersionDownloadUri(ctx context.Context, req *GetModelVersionDownloadUriRequest, opts ...call.Option) (*GetModelVersionDownloadUriResponse, error) { - wireReq, err := getModelVersionDownloadUriRequestToWire(req) +func (c *internalClient) GetModelVersionDownloadUri(ctx context.Context, req GetModelVersionDownloadUriRequest, opts ...call.Option) (*GetModelVersionDownloadUriResponse, error) { + wireReq, err := getModelVersionDownloadUriRequestToWire(&req) if err != nil { return nil, err } @@ -1631,8 +1628,8 @@ func (c *internalClient) GetModelVersionDownloadUri(ctx context.Context, req *Ge } // Gets the latest version of a registered model. -func (c *internalClient) ListLatestVersions(ctx context.Context, req *ListLatestVersionsRequest, opts ...call.Option) (*GetLatestVersionsResponse, error) { - wireReq, err := listLatestVersionsRequestToWire(req) +func (c *internalClient) ListLatestVersions(ctx context.Context, req ListLatestVersionsRequest, opts ...call.Option) (*GetLatestVersionsResponse, error) { + wireReq, err := listLatestVersionsRequestToWire(&req) if err != nil { return nil, err } @@ -1698,8 +1695,8 @@ func (c *internalClient) ListLatestVersions(ctx context.Context, req *ListLatest // Lists all available registered models, up to the limit specified in // __max_results__. -func (c *internalClient) ListRegisteredModels(ctx context.Context, req *ListRegisteredModelsRequest, opts ...call.Option) (*ListRegisteredModelsResponse, error) { - wireReq, err := listRegisteredModelsRequestToWire(req) +func (c *internalClient) ListRegisteredModels(ctx context.Context, req ListRegisteredModelsRequest, opts ...call.Option) (*ListRegisteredModelsResponse, error) { + wireReq, err := listRegisteredModelsRequestToWire(&req) if err != nil { return nil, err } @@ -1769,7 +1766,7 @@ func (c *internalClient) ListRegisteredModels(ctx context.Context, req *ListRegi // // For example: // -// for item, err := range c.ListRegisteredModelsIter(ctx, &ListRegisteredModelsRequest{}) { +// for item, err := range c.ListRegisteredModelsIter(ctx, ListRegisteredModelsRequest{}) { // if err != nil { // return err // } @@ -1781,16 +1778,13 @@ func (c *internalClient) ListRegisteredModels(ctx context.Context, req *ListRegi // // Callers who need custom pagination logic should use // ListRegisteredModels directly. -func (c *internalClient) ListRegisteredModelsIter(ctx context.Context, req *ListRegisteredModelsRequest, opts ...call.Option) iter.Seq2[*RegisteredModel, error] { +func (c *internalClient) ListRegisteredModelsIter(ctx context.Context, req ListRegisteredModelsRequest, opts ...call.Option) iter.Seq2[*RegisteredModel, error] { return func(yield func(*RegisteredModel, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListRegisteredModelsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListRegisteredModels(ctx, &pageReq, opts...) + resp, err := c.ListRegisteredModels(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1809,8 +1803,8 @@ func (c *internalClient) ListRegisteredModelsIter(ctx context.Context, req *List } // Renames a registered model. -func (c *internalClient) RenameRegisteredModel(ctx context.Context, req *RenameRegisteredModelRequest, opts ...call.Option) (*RenameRegisteredModelResponse, error) { - wireReq, err := renameRegisteredModelRequestToWire(req) +func (c *internalClient) RenameRegisteredModel(ctx context.Context, req RenameRegisteredModelRequest, opts ...call.Option) (*RenameRegisteredModelResponse, error) { + wireReq, err := renameRegisteredModelRequestToWire(&req) if err != nil { return nil, err } @@ -1875,8 +1869,8 @@ func (c *internalClient) RenameRegisteredModel(ctx context.Context, req *RenameR } // Searches for specific model versions based on the supplied __filter__. -func (c *internalClient) SearchModelVersions(ctx context.Context, req *SearchModelVersionsRequest, opts ...call.Option) (*SearchModelVersionsResponse, error) { - wireReq, err := searchModelVersionsRequestToWire(req) +func (c *internalClient) SearchModelVersions(ctx context.Context, req SearchModelVersionsRequest, opts ...call.Option) (*SearchModelVersionsResponse, error) { + wireReq, err := searchModelVersionsRequestToWire(&req) if err != nil { return nil, err } @@ -1952,7 +1946,7 @@ func (c *internalClient) SearchModelVersions(ctx context.Context, req *SearchMod // // For example: // -// for item, err := range c.SearchModelVersionsIter(ctx, &SearchModelVersionsRequest{}) { +// for item, err := range c.SearchModelVersionsIter(ctx, SearchModelVersionsRequest{}) { // if err != nil { // return err // } @@ -1964,16 +1958,13 @@ func (c *internalClient) SearchModelVersions(ctx context.Context, req *SearchMod // // Callers who need custom pagination logic should use // SearchModelVersions directly. -func (c *internalClient) SearchModelVersionsIter(ctx context.Context, req *SearchModelVersionsRequest, opts ...call.Option) iter.Seq2[*ModelVersion, error] { +func (c *internalClient) SearchModelVersionsIter(ctx context.Context, req SearchModelVersionsRequest, opts ...call.Option) iter.Seq2[*ModelVersion, error] { return func(yield func(*ModelVersion, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := SearchModelVersionsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.SearchModelVersions(ctx, &pageReq, opts...) + resp, err := c.SearchModelVersions(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1992,8 +1983,8 @@ func (c *internalClient) SearchModelVersionsIter(ctx context.Context, req *Searc } // Search for registered models based on the specified __filter__. -func (c *internalClient) SearchRegisteredModels(ctx context.Context, req *SearchRegisteredModelsRequest, opts ...call.Option) (*SearchRegisteredModelsResponse, error) { - wireReq, err := searchRegisteredModelsRequestToWire(req) +func (c *internalClient) SearchRegisteredModels(ctx context.Context, req SearchRegisteredModelsRequest, opts ...call.Option) (*SearchRegisteredModelsResponse, error) { + wireReq, err := searchRegisteredModelsRequestToWire(&req) if err != nil { return nil, err } @@ -2069,7 +2060,7 @@ func (c *internalClient) SearchRegisteredModels(ctx context.Context, req *Search // // For example: // -// for item, err := range c.SearchRegisteredModelsIter(ctx, &SearchRegisteredModelsRequest{}) { +// for item, err := range c.SearchRegisteredModelsIter(ctx, SearchRegisteredModelsRequest{}) { // if err != nil { // return err // } @@ -2081,16 +2072,13 @@ func (c *internalClient) SearchRegisteredModels(ctx context.Context, req *Search // // Callers who need custom pagination logic should use // SearchRegisteredModels directly. -func (c *internalClient) SearchRegisteredModelsIter(ctx context.Context, req *SearchRegisteredModelsRequest, opts ...call.Option) iter.Seq2[*RegisteredModel, error] { +func (c *internalClient) SearchRegisteredModelsIter(ctx context.Context, req SearchRegisteredModelsRequest, opts ...call.Option) iter.Seq2[*RegisteredModel, error] { return func(yield func(*RegisteredModel, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := SearchRegisteredModelsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.SearchRegisteredModels(ctx, &pageReq, opts...) + resp, err := c.SearchRegisteredModels(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -2109,8 +2097,8 @@ func (c *internalClient) SearchRegisteredModelsIter(ctx context.Context, req *Se } // Sets a model version tag. -func (c *internalClient) SetModelVersionTag(ctx context.Context, req *SetModelVersionTagRequest, opts ...call.Option) (*SetModelVersionTagResponse, error) { - wireReq, err := setModelVersionTagRequestToWire(req) +func (c *internalClient) SetModelVersionTag(ctx context.Context, req SetModelVersionTagRequest, opts ...call.Option) (*SetModelVersionTagResponse, error) { + wireReq, err := setModelVersionTagRequestToWire(&req) if err != nil { return nil, err } @@ -2169,8 +2157,8 @@ func (c *internalClient) SetModelVersionTag(ctx context.Context, req *SetModelVe } // Sets a tag on a registered model. -func (c *internalClient) SetRegisteredModelTag(ctx context.Context, req *SetRegisteredModelTagRequest, opts ...call.Option) (*SetRegisteredModelTagResponse, error) { - wireReq, err := setRegisteredModelTagRequestToWire(req) +func (c *internalClient) SetRegisteredModelTag(ctx context.Context, req SetRegisteredModelTagRequest, opts ...call.Option) (*SetRegisteredModelTagResponse, error) { + wireReq, err := setRegisteredModelTagRequestToWire(&req) if err != nil { return nil, err } @@ -2229,8 +2217,8 @@ func (c *internalClient) SetRegisteredModelTag(ctx context.Context, req *SetRegi } // Updates the model version. -func (c *internalClient) UpdateModelVersion(ctx context.Context, req *UpdateModelVersionRequest, opts ...call.Option) (*UpdateModelVersionResponse, error) { - wireReq, err := updateModelVersionRequestToWire(req) +func (c *internalClient) UpdateModelVersion(ctx context.Context, req UpdateModelVersionRequest, opts ...call.Option) (*UpdateModelVersionResponse, error) { + wireReq, err := updateModelVersionRequestToWire(&req) if err != nil { return nil, err } @@ -2295,8 +2283,8 @@ func (c *internalClient) UpdateModelVersion(ctx context.Context, req *UpdateMode } // Updates a registered model. -func (c *internalClient) UpdateRegisteredModel(ctx context.Context, req *UpdateRegisteredModelRequest, opts ...call.Option) (*UpdateRegisteredModelResponse, error) { - wireReq, err := updateRegisteredModelRequestToWire(req) +func (c *internalClient) UpdateRegisteredModel(ctx context.Context, req UpdateRegisteredModelRequest, opts ...call.Option) (*UpdateRegisteredModelResponse, error) { + wireReq, err := updateRegisteredModelRequestToWire(&req) if err != nil { return nil, err } diff --git a/modelregistry/v1/wire.go b/modelregistry/v1/wire.go old mode 100755 new mode 100644 index fb306ce..655d212 --- a/modelregistry/v1/wire.go +++ b/modelregistry/v1/wire.go @@ -3,15 +3,61 @@ package modelregistry import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type activityWire struct { - CreationTimestamp *int64 `json:"creation_timestamp,omitempty"` + CreationTimestamp *wireInt64 `json:"creation_timestamp,omitempty"` UserId *string `json:"user_id,omitempty"` ActivityType ActivityType `json:"activity_type,omitempty"` Comment *string `json:"comment,omitempty"` - LastUpdatedTimestamp *int64 `json:"last_updated_timestamp,omitempty"` + LastUpdatedTimestamp *wireInt64 `json:"last_updated_timestamp,omitempty"` FromStage *string `json:"from_stage,omitempty"` ToStage *string `json:"to_stage,omitempty"` SystemComment *string `json:"system_comment,omitempty"` @@ -23,12 +69,20 @@ func activityFromWire(w *activityWire) (*Activity, error) { if w == nil { return nil, nil } + creationTimestampPublicValue, err := int64FromWire(w.CreationTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Activity.CreationTimestamp", err) + } + lastUpdatedTimestampPublicValue, err := int64FromWire(w.LastUpdatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Activity.LastUpdatedTimestamp", err) + } return &Activity{ - CreationTimestamp: w.CreationTimestamp, + CreationTimestamp: creationTimestampPublicValue, UserId: w.UserId, ActivityType: w.ActivityType, Comment: w.Comment, - LastUpdatedTimestamp: w.LastUpdatedTimestamp, + LastUpdatedTimestamp: lastUpdatedTimestampPublicValue, FromStage: w.FromStage, ToStage: w.ToStage, SystemComment: w.SystemComment, @@ -76,11 +130,11 @@ func approveTransitionResponseFromWire(w *approveTransitionResponseWire) (*Appro } type commentObjectWire struct { - CreationTimestamp *int64 `json:"creation_timestamp,omitempty"` + CreationTimestamp *wireInt64 `json:"creation_timestamp,omitempty"` UserId *string `json:"user_id,omitempty"` ActivityType ActivityType `json:"activity_type,omitempty"` Comment *string `json:"comment,omitempty"` - LastUpdatedTimestamp *int64 `json:"last_updated_timestamp,omitempty"` + LastUpdatedTimestamp *wireInt64 `json:"last_updated_timestamp,omitempty"` FromStage *string `json:"from_stage,omitempty"` ToStage *string `json:"to_stage,omitempty"` SystemComment *string `json:"system_comment,omitempty"` @@ -92,12 +146,20 @@ func commentObjectFromWire(w *commentObjectWire) (*CommentObject, error) { if w == nil { return nil, nil } + creationTimestampPublicValue, err := int64FromWire(w.CreationTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CommentObject.CreationTimestamp", err) + } + lastUpdatedTimestampPublicValue, err := int64FromWire(w.LastUpdatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CommentObject.LastUpdatedTimestamp", err) + } return &CommentObject{ - CreationTimestamp: w.CreationTimestamp, + CreationTimestamp: creationTimestampPublicValue, UserId: w.UserId, ActivityType: w.ActivityType, Comment: w.Comment, - LastUpdatedTimestamp: w.LastUpdatedTimestamp, + LastUpdatedTimestamp: lastUpdatedTimestampPublicValue, FromStage: w.FromStage, ToStage: w.ToStage, SystemComment: w.SystemComment, @@ -646,16 +708,20 @@ func listLatestVersionsRequestToWire(v *ListLatestVersionsRequest) (*listLatestV } type listRegisteredModelsRequestWire struct { - MaxResults *int64 `json:"max_results,omitempty"` - PageToken *string `json:"page_token,omitempty"` + MaxResults *wireInt64 `json:"max_results,omitempty"` + PageToken *string `json:"page_token,omitempty"` } func listRegisteredModelsRequestToWire(v *ListRegisteredModelsRequest) (*listRegisteredModelsRequestWire, error) { if v == nil { return nil, nil } + maxResultsWireValue, err := int64ToWire(v.MaxResults) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListRegisteredModelsRequest.MaxResults", err) + } return &listRegisteredModelsRequestWire{ - MaxResults: v.MaxResults, + MaxResults: maxResultsWireValue, PageToken: v.PageToken, }, nil } @@ -683,18 +749,22 @@ type listRegistryWebhooksRequestWire struct { ModelName *string `json:"model_name,omitempty"` Events []RegistryWebhookEvent `json:"events,omitempty"` PageToken *string `json:"page_token,omitempty"` - MaxResults *int64 `json:"max_results,omitempty"` + MaxResults *wireInt64 `json:"max_results,omitempty"` } func listRegistryWebhooksRequestToWire(v *ListRegistryWebhooksRequest) (*listRegistryWebhooksRequestWire, error) { if v == nil { return nil, nil } + maxResultsWireValue, err := int64ToWire(v.MaxResults) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListRegistryWebhooksRequest.MaxResults", err) + } return &listRegistryWebhooksRequestWire{ ModelName: v.ModelName, Events: v.Events, PageToken: v.PageToken, - MaxResults: v.MaxResults, + MaxResults: maxResultsWireValue, }, nil } @@ -752,8 +822,8 @@ func listTransitionResponseFromWire(w *listTransitionResponseWire) (*ListTransit type modelVersionWire struct { Name *string `json:"name,omitempty"` Version *string `json:"version,omitempty"` - CreationTimestamp *int64 `json:"creation_timestamp,omitempty"` - LastUpdatedTimestamp *int64 `json:"last_updated_timestamp,omitempty"` + CreationTimestamp *wireInt64 `json:"creation_timestamp,omitempty"` + LastUpdatedTimestamp *wireInt64 `json:"last_updated_timestamp,omitempty"` UserId *string `json:"user_id,omitempty"` CurrentStage *string `json:"current_stage,omitempty"` Description *string `json:"description,omitempty"` @@ -769,6 +839,14 @@ func modelVersionFromWire(w *modelVersionWire) (*ModelVersion, error) { if w == nil { return nil, nil } + creationTimestampPublicValue, err := int64FromWire(w.CreationTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ModelVersion.CreationTimestamp", err) + } + lastUpdatedTimestampPublicValue, err := int64FromWire(w.LastUpdatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ModelVersion.LastUpdatedTimestamp", err) + } tagsPublicValue, err := convertSlice(w.Tags, modelVersionTagFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "ModelVersion.Tags", err) @@ -776,8 +854,8 @@ func modelVersionFromWire(w *modelVersionWire) (*ModelVersion, error) { return &ModelVersion{ Name: w.Name, Version: w.Version, - CreationTimestamp: w.CreationTimestamp, - LastUpdatedTimestamp: w.LastUpdatedTimestamp, + CreationTimestamp: creationTimestampPublicValue, + LastUpdatedTimestamp: lastUpdatedTimestampPublicValue, UserId: w.UserId, CurrentStage: w.CurrentStage, Description: w.Description, @@ -793,8 +871,8 @@ func modelVersionFromWire(w *modelVersionWire) (*ModelVersion, error) { type modelVersionDatabricksWire struct { Name *string `json:"name,omitempty"` Version *string `json:"version,omitempty"` - CreationTimestamp *int64 `json:"creation_timestamp,omitempty"` - LastUpdatedTimestamp *int64 `json:"last_updated_timestamp,omitempty"` + CreationTimestamp *wireInt64 `json:"creation_timestamp,omitempty"` + LastUpdatedTimestamp *wireInt64 `json:"last_updated_timestamp,omitempty"` UserId *string `json:"user_id,omitempty"` CurrentStage *string `json:"current_stage,omitempty"` Description *string `json:"description,omitempty"` @@ -814,6 +892,14 @@ func modelVersionDatabricksFromWire(w *modelVersionDatabricksWire) (*ModelVersio if w == nil { return nil, nil } + creationTimestampPublicValue, err := int64FromWire(w.CreationTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ModelVersionDatabricks.CreationTimestamp", err) + } + lastUpdatedTimestampPublicValue, err := int64FromWire(w.LastUpdatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ModelVersionDatabricks.LastUpdatedTimestamp", err) + } openRequestsPublicValue, err := convertSlice(w.OpenRequests, activityFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "ModelVersionDatabricks.OpenRequests", err) @@ -829,8 +915,8 @@ func modelVersionDatabricksFromWire(w *modelVersionDatabricksWire) (*ModelVersio return &ModelVersionDatabricks{ Name: w.Name, Version: w.Version, - CreationTimestamp: w.CreationTimestamp, - LastUpdatedTimestamp: w.LastUpdatedTimestamp, + CreationTimestamp: creationTimestampPublicValue, + LastUpdatedTimestamp: lastUpdatedTimestampPublicValue, UserId: w.UserId, CurrentStage: w.CurrentStage, Description: w.Description, @@ -874,8 +960,8 @@ func modelVersionTagFromWire(w *modelVersionTagWire) (*ModelVersionTag, error) { type registeredModelWire struct { Name *string `json:"name,omitempty"` - CreationTimestamp *int64 `json:"creation_timestamp,omitempty"` - LastUpdatedTimestamp *int64 `json:"last_updated_timestamp,omitempty"` + CreationTimestamp *wireInt64 `json:"creation_timestamp,omitempty"` + LastUpdatedTimestamp *wireInt64 `json:"last_updated_timestamp,omitempty"` UserId *string `json:"user_id,omitempty"` Description *string `json:"description,omitempty"` LatestVersions []modelVersionWire `json:"latest_versions,omitempty"` @@ -886,6 +972,14 @@ func registeredModelFromWire(w *registeredModelWire) (*RegisteredModel, error) { if w == nil { return nil, nil } + creationTimestampPublicValue, err := int64FromWire(w.CreationTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RegisteredModel.CreationTimestamp", err) + } + lastUpdatedTimestampPublicValue, err := int64FromWire(w.LastUpdatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RegisteredModel.LastUpdatedTimestamp", err) + } latestVersionsPublicValue, err := convertSlice(w.LatestVersions, modelVersionFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "RegisteredModel.LatestVersions", err) @@ -896,8 +990,8 @@ func registeredModelFromWire(w *registeredModelWire) (*RegisteredModel, error) { } return &RegisteredModel{ Name: w.Name, - CreationTimestamp: w.CreationTimestamp, - LastUpdatedTimestamp: w.LastUpdatedTimestamp, + CreationTimestamp: creationTimestampPublicValue, + LastUpdatedTimestamp: lastUpdatedTimestampPublicValue, UserId: w.UserId, Description: w.Description, LatestVersions: latestVersionsPublicValue, @@ -907,8 +1001,8 @@ func registeredModelFromWire(w *registeredModelWire) (*RegisteredModel, error) { type registeredModelDatabricksWire struct { Name *string `json:"name,omitempty"` - CreationTimestamp *int64 `json:"creation_timestamp,omitempty"` - LastUpdatedTimestamp *int64 `json:"last_updated_timestamp,omitempty"` + CreationTimestamp *wireInt64 `json:"creation_timestamp,omitempty"` + LastUpdatedTimestamp *wireInt64 `json:"last_updated_timestamp,omitempty"` UserId *string `json:"user_id,omitempty"` Description *string `json:"description,omitempty"` LatestVersions []modelVersionWire `json:"latest_versions,omitempty"` @@ -921,6 +1015,14 @@ func registeredModelDatabricksFromWire(w *registeredModelDatabricksWire) (*Regis if w == nil { return nil, nil } + creationTimestampPublicValue, err := int64FromWire(w.CreationTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RegisteredModelDatabricks.CreationTimestamp", err) + } + lastUpdatedTimestampPublicValue, err := int64FromWire(w.LastUpdatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RegisteredModelDatabricks.LastUpdatedTimestamp", err) + } latestVersionsPublicValue, err := convertSlice(w.LatestVersions, modelVersionFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "RegisteredModelDatabricks.LatestVersions", err) @@ -931,8 +1033,8 @@ func registeredModelDatabricksFromWire(w *registeredModelDatabricksWire) (*Regis } return &RegisteredModelDatabricks{ Name: w.Name, - CreationTimestamp: w.CreationTimestamp, - LastUpdatedTimestamp: w.LastUpdatedTimestamp, + CreationTimestamp: creationTimestampPublicValue, + LastUpdatedTimestamp: lastUpdatedTimestampPublicValue, UserId: w.UserId, Description: w.Description, LatestVersions: latestVersionsPublicValue, @@ -970,8 +1072,8 @@ func registeredModelTagFromWire(w *registeredModelTagWire) (*RegisteredModelTag, type registryWebhookWire struct { Id *string `json:"id,omitempty"` Events []RegistryWebhookEvent `json:"events,omitempty"` - CreationTimestamp *int64 `json:"creation_timestamp,omitempty"` - LastUpdatedTimestamp *int64 `json:"last_updated_timestamp,omitempty"` + CreationTimestamp *wireInt64 `json:"creation_timestamp,omitempty"` + LastUpdatedTimestamp *wireInt64 `json:"last_updated_timestamp,omitempty"` Description *string `json:"description,omitempty"` Status RegistryWebhookStatus `json:"status,omitempty"` HttpUrlSpec *httpUrlSpecWire `json:"http_url_spec,omitempty"` @@ -983,6 +1085,14 @@ func registryWebhookFromWire(w *registryWebhookWire) (*RegistryWebhook, error) { if w == nil { return nil, nil } + creationTimestampPublicValue, err := int64FromWire(w.CreationTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RegistryWebhook.CreationTimestamp", err) + } + lastUpdatedTimestampPublicValue, err := int64FromWire(w.LastUpdatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RegistryWebhook.LastUpdatedTimestamp", err) + } httpUrlSpecPublicValue, err := httpUrlSpecFromWire(w.HttpUrlSpec) if err != nil { return nil, fmt.Errorf("%s: %w", "RegistryWebhook.HttpUrlSpec", err) @@ -994,8 +1104,8 @@ func registryWebhookFromWire(w *registryWebhookWire) (*RegistryWebhook, error) { return &RegistryWebhook{ Id: w.Id, Events: w.Events, - CreationTimestamp: w.CreationTimestamp, - LastUpdatedTimestamp: w.LastUpdatedTimestamp, + CreationTimestamp: creationTimestampPublicValue, + LastUpdatedTimestamp: lastUpdatedTimestampPublicValue, Description: w.Description, Status: w.Status, HttpUrlSpec: httpUrlSpecPublicValue, @@ -1073,19 +1183,23 @@ func renameRegisteredModelResponseFromWire(w *renameRegisteredModelResponseWire) } type searchModelVersionsRequestWire struct { - Filter *string `json:"filter,omitempty"` - MaxResults *int64 `json:"max_results,omitempty"` - OrderBy []string `json:"order_by,omitempty"` - PageToken *string `json:"page_token,omitempty"` + Filter *string `json:"filter,omitempty"` + MaxResults *wireInt64 `json:"max_results,omitempty"` + OrderBy []string `json:"order_by,omitempty"` + PageToken *string `json:"page_token,omitempty"` } func searchModelVersionsRequestToWire(v *SearchModelVersionsRequest) (*searchModelVersionsRequestWire, error) { if v == nil { return nil, nil } + maxResultsWireValue, err := int64ToWire(v.MaxResults) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SearchModelVersionsRequest.MaxResults", err) + } return &searchModelVersionsRequestWire{ Filter: v.Filter, - MaxResults: v.MaxResults, + MaxResults: maxResultsWireValue, OrderBy: v.OrderBy, PageToken: v.PageToken, }, nil @@ -1111,19 +1225,23 @@ func searchModelVersionsResponseFromWire(w *searchModelVersionsResponseWire) (*S } type searchRegisteredModelsRequestWire struct { - Filter *string `json:"filter,omitempty"` - MaxResults *int64 `json:"max_results,omitempty"` - OrderBy []string `json:"order_by,omitempty"` - PageToken *string `json:"page_token,omitempty"` + Filter *string `json:"filter,omitempty"` + MaxResults *wireInt64 `json:"max_results,omitempty"` + OrderBy []string `json:"order_by,omitempty"` + PageToken *string `json:"page_token,omitempty"` } func searchRegisteredModelsRequestToWire(v *SearchRegisteredModelsRequest) (*searchRegisteredModelsRequestWire, error) { if v == nil { return nil, nil } + maxResultsWireValue, err := int64ToWire(v.MaxResults) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SearchRegisteredModelsRequest.MaxResults", err) + } return &searchRegisteredModelsRequestWire{ Filter: v.Filter, - MaxResults: v.MaxResults, + MaxResults: maxResultsWireValue, OrderBy: v.OrderBy, PageToken: v.PageToken, }, nil @@ -1253,11 +1371,11 @@ func transitionModelVersionStageDatabricksResponseFromWire(w *transitionModelVer } type transitionRequestWire struct { - CreationTimestamp *int64 `json:"creation_timestamp,omitempty"` + CreationTimestamp *wireInt64 `json:"creation_timestamp,omitempty"` UserId *string `json:"user_id,omitempty"` ActivityType ActivityType `json:"activity_type,omitempty"` Comment *string `json:"comment,omitempty"` - LastUpdatedTimestamp *int64 `json:"last_updated_timestamp,omitempty"` + LastUpdatedTimestamp *wireInt64 `json:"last_updated_timestamp,omitempty"` FromStage *string `json:"from_stage,omitempty"` ToStage *string `json:"to_stage,omitempty"` SystemComment *string `json:"system_comment,omitempty"` @@ -1269,12 +1387,20 @@ func transitionRequestFromWire(w *transitionRequestWire) (*TransitionRequest, er if w == nil { return nil, nil } + creationTimestampPublicValue, err := int64FromWire(w.CreationTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TransitionRequest.CreationTimestamp", err) + } + lastUpdatedTimestampPublicValue, err := int64FromWire(w.LastUpdatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TransitionRequest.LastUpdatedTimestamp", err) + } return &TransitionRequest{ - CreationTimestamp: w.CreationTimestamp, + CreationTimestamp: creationTimestampPublicValue, UserId: w.UserId, ActivityType: w.ActivityType, Comment: w.Comment, - LastUpdatedTimestamp: w.LastUpdatedTimestamp, + LastUpdatedTimestamp: lastUpdatedTimestampPublicValue, FromStage: w.FromStage, ToStage: w.ToStage, SystemComment: w.SystemComment, diff --git a/modelserving/CHANGELOG.md b/modelserving/CHANGELOG.md index 6224c04..19f237c 100644 --- a/modelserving/CHANGELOG.md +++ b/modelserving/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/modelserving/go.mod b/modelserving/go.mod index fc5603d..0461ae0 100644 --- a/modelserving/go.mod +++ b/modelserving/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/modelserving/internal/version.go b/modelserving/internal/version.go index f9121e0..a0015b7 100644 --- a/modelserving/internal/version.go +++ b/modelserving/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-modelserving" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/modelserving/v1/client.go b/modelserving/v1/client.go old mode 100755 new mode 100644 index 7abfc43..41b62d2 --- a/modelserving/v1/client.go +++ b/modelserving/v1/client.go @@ -76,8 +76,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Create a new serving endpoint. -func (c *internalClient) createInferenceEndpointBase(ctx context.Context, req *CreateInferenceEndpointRequest, opts ...call.Option) (*InferenceEndpointDetailed, error) { - wireReq, err := createInferenceEndpointRequestToWire(req) +func (c *internalClient) createInferenceEndpointBase(ctx context.Context, req CreateInferenceEndpointRequest, opts ...call.Option) (*InferenceEndpointDetailed, error) { + wireReq, err := createInferenceEndpointRequestToWire(&req) if err != nil { return nil, err } @@ -142,7 +142,7 @@ func (c *internalClient) createInferenceEndpointBase(ctx context.Context, req *C } // Create a new serving endpoint. -func (c *internalClient) CreateInferenceEndpoint(ctx context.Context, req *CreateInferenceEndpointRequest, opts ...call.Option) (*CreateInferenceEndpointWaiter, error) { +func (c *internalClient) CreateInferenceEndpoint(ctx context.Context, req CreateInferenceEndpointRequest, opts ...call.Option) (*CreateInferenceEndpointWaiter, error) { if req.Name == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "Name") } @@ -159,13 +159,18 @@ func (c *internalClient) CreateInferenceEndpoint(ctx context.Context, req *Creat // CreateInferenceEndpointWaiter tracks the state of the operation started by CreateInferenceEndpoint. type CreateInferenceEndpointWaiter struct { - poll func(context.Context, *GetInferenceEndpointRequest, ...call.Option) (*InferenceEndpointDetailed, error) + poll func(context.Context, GetInferenceEndpointRequest, ...call.Option) (*InferenceEndpointDetailed, error) name string } +// GetName returns the Name value used to identify the operation. +func (w *CreateInferenceEndpointWaiter) GetName() string { + return w.name +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *CreateInferenceEndpointWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetInferenceEndpointRequest{ + pollResp, err := w.poll(ctx, GetInferenceEndpointRequest{ Name: &w.name, }, opts...) if err != nil { @@ -193,7 +198,7 @@ func (w *CreateInferenceEndpointWaiter) Done(ctx context.Context, opts ...call.O func (w *CreateInferenceEndpointWaiter) Wait(ctx context.Context, opts ...lro.Option) (*InferenceEndpointDetailed, error) { var result *InferenceEndpointDetailed poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetInferenceEndpointRequest{ + pollResp, err := w.poll(ctx, GetInferenceEndpointRequest{ Name: &w.name, }) if err != nil { @@ -227,8 +232,8 @@ func (w *CreateInferenceEndpointWaiter) Wait(ctx context.Context, opts ...lro.Op } // Create a new PT serving endpoint. -func (c *internalClient) createProvisionedThroughputInferenceEndpointBase(ctx context.Context, req *CreatePtEndpointRequest, opts ...call.Option) (*InferenceEndpointDetailed, error) { - wireReq, err := createPtEndpointRequestToWire(req) +func (c *internalClient) createProvisionedThroughputInferenceEndpointBase(ctx context.Context, req CreatePtEndpointRequest, opts ...call.Option) (*InferenceEndpointDetailed, error) { + wireReq, err := createPtEndpointRequestToWire(&req) if err != nil { return nil, err } @@ -293,7 +298,7 @@ func (c *internalClient) createProvisionedThroughputInferenceEndpointBase(ctx co } // Create a new PT serving endpoint. -func (c *internalClient) CreateProvisionedThroughputInferenceEndpoint(ctx context.Context, req *CreatePtEndpointRequest, opts ...call.Option) (*CreateProvisionedThroughputInferenceEndpointWaiter, error) { +func (c *internalClient) CreateProvisionedThroughputInferenceEndpoint(ctx context.Context, req CreatePtEndpointRequest, opts ...call.Option) (*CreateProvisionedThroughputInferenceEndpointWaiter, error) { if req.Name == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "Name") } @@ -310,13 +315,18 @@ func (c *internalClient) CreateProvisionedThroughputInferenceEndpoint(ctx contex // CreateProvisionedThroughputInferenceEndpointWaiter tracks the state of the operation started by CreateProvisionedThroughputInferenceEndpoint. type CreateProvisionedThroughputInferenceEndpointWaiter struct { - poll func(context.Context, *GetInferenceEndpointRequest, ...call.Option) (*InferenceEndpointDetailed, error) + poll func(context.Context, GetInferenceEndpointRequest, ...call.Option) (*InferenceEndpointDetailed, error) name string } +// GetName returns the Name value used to identify the operation. +func (w *CreateProvisionedThroughputInferenceEndpointWaiter) GetName() string { + return w.name +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *CreateProvisionedThroughputInferenceEndpointWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetInferenceEndpointRequest{ + pollResp, err := w.poll(ctx, GetInferenceEndpointRequest{ Name: &w.name, }, opts...) if err != nil { @@ -344,7 +354,7 @@ func (w *CreateProvisionedThroughputInferenceEndpointWaiter) Done(ctx context.Co func (w *CreateProvisionedThroughputInferenceEndpointWaiter) Wait(ctx context.Context, opts ...lro.Option) (*InferenceEndpointDetailed, error) { var result *InferenceEndpointDetailed poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetInferenceEndpointRequest{ + pollResp, err := w.poll(ctx, GetInferenceEndpointRequest{ Name: &w.name, }) if err != nil { @@ -378,7 +388,7 @@ func (w *CreateProvisionedThroughputInferenceEndpointWaiter) Wait(ctx context.Co } // Delete a serving endpoint. -func (c *internalClient) DeleteInferenceEndpoint(ctx context.Context, req *DeleteInferenceEndpointRequest, opts ...call.Option) (*DeleteInferenceEndpointResponse, error) { +func (c *internalClient) DeleteInferenceEndpoint(ctx context.Context, req DeleteInferenceEndpointRequest, opts ...call.Option) (*DeleteInferenceEndpointResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -392,7 +402,11 @@ func (c *internalClient) DeleteInferenceEndpoint(ctx context.Context, req *Delet } pb := pathBuilder{} pb.literal("/api/2.0/serving-endpoints/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -433,7 +447,7 @@ func (c *internalClient) DeleteInferenceEndpoint(ctx context.Context, req *Delet // Retrieves the metrics associated with the provided serving endpoint in either // Prometheus or OpenMetrics exposition format. -func (c *internalClient) GetExportEndpointMetrics(ctx context.Context, req *GetExportEndpointMetricsRequest, opts ...call.Option) (*ExportMetricsResponse, error) { +func (c *internalClient) GetExportEndpointMetrics(ctx context.Context, req GetExportEndpointMetricsRequest, opts ...call.Option) (*ExportMetricsResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -448,7 +462,11 @@ func (c *internalClient) GetExportEndpointMetrics(ctx context.Context, req *GetE } pb := pathBuilder{} pb.literal("/api/2.0/serving-endpoints/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/metrics") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -489,7 +507,7 @@ func (c *internalClient) GetExportEndpointMetrics(ctx context.Context, req *GetE } // Retrieves the details for a single serving endpoint. -func (c *internalClient) GetInferenceEndpoint(ctx context.Context, req *GetInferenceEndpointRequest, opts ...call.Option) (*InferenceEndpointDetailed, error) { +func (c *internalClient) GetInferenceEndpoint(ctx context.Context, req GetInferenceEndpointRequest, opts ...call.Option) (*InferenceEndpointDetailed, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -503,7 +521,11 @@ func (c *internalClient) GetInferenceEndpoint(ctx context.Context, req *GetInfer } pb := pathBuilder{} pb.literal("/api/2.0/serving-endpoints/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -551,7 +573,7 @@ func (c *internalClient) GetInferenceEndpoint(ctx context.Context, req *GetInfer // Get the query schema of the serving endpoint in OpenAPI format. The schema // contains information for the supported paths, input and output format and // datatypes. -func (c *internalClient) GetInferenceEndpointSchema(ctx context.Context, req *GetInferenceEndpointSchemaRequest, opts ...call.Option) (*GetOpenApiResponse, error) { +func (c *internalClient) GetInferenceEndpointSchema(ctx context.Context, req GetInferenceEndpointSchemaRequest, opts ...call.Option) (*GetOpenApiResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -566,7 +588,11 @@ func (c *internalClient) GetInferenceEndpointSchema(ctx context.Context, req *Ge } pb := pathBuilder{} pb.literal("/api/2.0/serving-endpoints/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/openapi") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -607,7 +633,7 @@ func (c *internalClient) GetInferenceEndpointSchema(ctx context.Context, req *Ge } // Retrieves the build logs associated with the provided served model. -func (c *internalClient) GetServedModelBuildLogs(ctx context.Context, req *GetServedModelBuildLogsRequest, opts ...call.Option) (*GetServedModelBuildLogsResponse, error) { +func (c *internalClient) GetServedModelBuildLogs(ctx context.Context, req GetServedModelBuildLogsRequest, opts ...call.Option) (*GetServedModelBuildLogsResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -621,9 +647,17 @@ func (c *internalClient) GetServedModelBuildLogs(ctx context.Context, req *GetSe } pb := pathBuilder{} pb.literal("/api/2.0/serving-endpoints/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/served-models/") - pb.singleSegment(*req.ServedModelName) + if req.ServedModelName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ServedModelName) + } pb.literal("/build-logs") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -670,7 +704,7 @@ func (c *internalClient) GetServedModelBuildLogs(ctx context.Context, req *GetSe } // Retrieves the service logs associated with the provided served model. -func (c *internalClient) GetServedModelLogs(ctx context.Context, req *GetServedModelLogsRequest, opts ...call.Option) (*GetServedModelLogsResponse, error) { +func (c *internalClient) GetServedModelLogs(ctx context.Context, req GetServedModelLogsRequest, opts ...call.Option) (*GetServedModelLogsResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -684,9 +718,17 @@ func (c *internalClient) GetServedModelLogs(ctx context.Context, req *GetServedM } pb := pathBuilder{} pb.literal("/api/2.0/serving-endpoints/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/served-models/") - pb.singleSegment(*req.ServedModelName) + if req.ServedModelName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ServedModelName) + } pb.literal("/logs") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -733,7 +775,7 @@ func (c *internalClient) GetServedModelLogs(ctx context.Context, req *GetServedM } // Get all serving endpoints. -func (c *internalClient) ListInferenceEndpoints(ctx context.Context, req *ListInferenceEndpointsRequest, opts ...call.Option) (*ListInferenceEndpointsResponse, error) { +func (c *internalClient) ListInferenceEndpoints(ctx context.Context, req ListInferenceEndpointsRequest, opts ...call.Option) (*ListInferenceEndpointsResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -791,8 +833,8 @@ func (c *internalClient) ListInferenceEndpoints(ctx context.Context, req *ListIn // Used to batch add and delete tags from a serving endpoint with a single API // call. -func (c *internalClient) PatchInferenceEndpointTags(ctx context.Context, req *PatchInferenceEndpointTagsRequest, opts ...call.Option) (*PatchInferenceEndpointTagsResponse, error) { - wireReq, err := patchInferenceEndpointTagsRequestToWire(req) +func (c *internalClient) PatchInferenceEndpointTags(ctx context.Context, req PatchInferenceEndpointTagsRequest, opts ...call.Option) (*PatchInferenceEndpointTagsResponse, error) { + wireReq, err := patchInferenceEndpointTagsRequestToWire(&req) if err != nil { return nil, err } @@ -813,7 +855,11 @@ func (c *internalClient) PatchInferenceEndpointTags(ctx context.Context, req *Pa } pb := pathBuilder{} pb.literal("/api/2.0/serving-endpoints/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/tags") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -861,8 +907,8 @@ func (c *internalClient) PatchInferenceEndpointTags(ctx context.Context, req *Pa } // Updates the telemetry configuration of a serving endpoint. -func (c *internalClient) PatchInferenceEndpointTelemetryConfig(ctx context.Context, req *PatchInferenceEndpointTelemetryConfigRequest, opts ...call.Option) (*InferenceEndpointDetailed, error) { - wireReq, err := patchInferenceEndpointTelemetryConfigRequestToWire(req) +func (c *internalClient) PatchInferenceEndpointTelemetryConfig(ctx context.Context, req PatchInferenceEndpointTelemetryConfigRequest, opts ...call.Option) (*InferenceEndpointDetailed, error) { + wireReq, err := patchInferenceEndpointTelemetryConfigRequestToWire(&req) if err != nil { return nil, err } @@ -883,7 +929,11 @@ func (c *internalClient) PatchInferenceEndpointTelemetryConfig(ctx context.Conte } pb := pathBuilder{} pb.literal("/api/2.0/serving-endpoints/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/telemetry-config") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -933,8 +983,8 @@ func (c *internalClient) PatchInferenceEndpointTelemetryConfig(ctx context.Conte // Used to update the AI Gateway of a serving endpoint. NOTE: External model, // provisioned throughput, and pay-per-token endpoints are fully supported; // agent endpoints currently only support inference tables. -func (c *internalClient) PutInferenceEndpointAiGateway(ctx context.Context, req *PutInferenceEndpointAiGatewayRequest, opts ...call.Option) (*PutInferenceEndpointAiGatewayResponse, error) { - wireReq, err := putInferenceEndpointAiGatewayRequestToWire(req) +func (c *internalClient) PutInferenceEndpointAiGateway(ctx context.Context, req PutInferenceEndpointAiGatewayRequest, opts ...call.Option) (*PutInferenceEndpointAiGatewayResponse, error) { + wireReq, err := putInferenceEndpointAiGatewayRequestToWire(&req) if err != nil { return nil, err } @@ -955,7 +1005,11 @@ func (c *internalClient) PutInferenceEndpointAiGateway(ctx context.Context, req } pb := pathBuilder{} pb.literal("/api/2.0/serving-endpoints/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/ai-gateway") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1006,8 +1060,8 @@ func (c *internalClient) PutInferenceEndpointAiGateway(ctx context.Context, req // compute configuration of those served entities, and the endpoint's traffic // config. An endpoint that already has an update in progress can not be updated // until the current update completes or fails. -func (c *internalClient) putInferenceEndpointConfigBase(ctx context.Context, req *PutInferenceEndpointConfigRequest, opts ...call.Option) (*InferenceEndpointDetailed, error) { - wireReq, err := putInferenceEndpointConfigRequestToWire(req) +func (c *internalClient) putInferenceEndpointConfigBase(ctx context.Context, req PutInferenceEndpointConfigRequest, opts ...call.Option) (*InferenceEndpointDetailed, error) { + wireReq, err := putInferenceEndpointConfigRequestToWire(&req) if err != nil { return nil, err } @@ -1028,7 +1082,11 @@ func (c *internalClient) putInferenceEndpointConfigBase(ctx context.Context, req } pb := pathBuilder{} pb.literal("/api/2.0/serving-endpoints/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/config") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1079,7 +1137,7 @@ func (c *internalClient) putInferenceEndpointConfigBase(ctx context.Context, req // compute configuration of those served entities, and the endpoint's traffic // config. An endpoint that already has an update in progress can not be updated // until the current update completes or fails. -func (c *internalClient) PutInferenceEndpointConfig(ctx context.Context, req *PutInferenceEndpointConfigRequest, opts ...call.Option) (*PutInferenceEndpointConfigWaiter, error) { +func (c *internalClient) PutInferenceEndpointConfig(ctx context.Context, req PutInferenceEndpointConfigRequest, opts ...call.Option) (*PutInferenceEndpointConfigWaiter, error) { if req.Name == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "Name") } @@ -1096,13 +1154,18 @@ func (c *internalClient) PutInferenceEndpointConfig(ctx context.Context, req *Pu // PutInferenceEndpointConfigWaiter tracks the state of the operation started by PutInferenceEndpointConfig. type PutInferenceEndpointConfigWaiter struct { - poll func(context.Context, *GetInferenceEndpointRequest, ...call.Option) (*InferenceEndpointDetailed, error) + poll func(context.Context, GetInferenceEndpointRequest, ...call.Option) (*InferenceEndpointDetailed, error) name string } +// GetName returns the Name value used to identify the operation. +func (w *PutInferenceEndpointConfigWaiter) GetName() string { + return w.name +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *PutInferenceEndpointConfigWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetInferenceEndpointRequest{ + pollResp, err := w.poll(ctx, GetInferenceEndpointRequest{ Name: &w.name, }, opts...) if err != nil { @@ -1130,7 +1193,7 @@ func (w *PutInferenceEndpointConfigWaiter) Done(ctx context.Context, opts ...cal func (w *PutInferenceEndpointConfigWaiter) Wait(ctx context.Context, opts ...lro.Option) (*InferenceEndpointDetailed, error) { var result *InferenceEndpointDetailed poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetInferenceEndpointRequest{ + pollResp, err := w.poll(ctx, GetInferenceEndpointRequest{ Name: &w.name, }) if err != nil { @@ -1164,8 +1227,8 @@ func (w *PutInferenceEndpointConfigWaiter) Wait(ctx context.Context, opts ...lro } // Deprecated: Please use AI Gateway to manage rate limits instead. -func (c *internalClient) PutInferenceEndpointRateLimits(ctx context.Context, req *PutInferenceEndpointRateLimitsRequest, opts ...call.Option) (*PutInferenceEndpointRateLimitsResponse, error) { - wireReq, err := putInferenceEndpointRateLimitsRequestToWire(req) +func (c *internalClient) PutInferenceEndpointRateLimits(ctx context.Context, req PutInferenceEndpointRateLimitsRequest, opts ...call.Option) (*PutInferenceEndpointRateLimitsResponse, error) { + wireReq, err := putInferenceEndpointRateLimitsRequestToWire(&req) if err != nil { return nil, err } @@ -1186,7 +1249,11 @@ func (c *internalClient) PutInferenceEndpointRateLimits(ctx context.Context, req } pb := pathBuilder{} pb.literal("/api/2.0/serving-endpoints/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/rate-limits") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1236,8 +1303,8 @@ func (c *internalClient) PutInferenceEndpointRateLimits(ctx context.Context, req // Updates any combination of the pt endpoint's served entities, the compute // configuration of those served entities, and the endpoint's traffic config. // Updates are instantaneous and endpoint should be updated instantly -func (c *internalClient) putProvisionedThroughputInferenceEndpointConfigBase(ctx context.Context, req *PutPtEndpointConfigRequest, opts ...call.Option) (*InferenceEndpointDetailed, error) { - wireReq, err := putPtEndpointConfigRequestToWire(req) +func (c *internalClient) putProvisionedThroughputInferenceEndpointConfigBase(ctx context.Context, req PutPtEndpointConfigRequest, opts ...call.Option) (*InferenceEndpointDetailed, error) { + wireReq, err := putPtEndpointConfigRequestToWire(&req) if err != nil { return nil, err } @@ -1258,7 +1325,11 @@ func (c *internalClient) putProvisionedThroughputInferenceEndpointConfigBase(ctx } pb := pathBuilder{} pb.literal("/api/2.0/serving-endpoints/pt/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/config") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1308,7 +1379,7 @@ func (c *internalClient) putProvisionedThroughputInferenceEndpointConfigBase(ctx // Updates any combination of the pt endpoint's served entities, the compute // configuration of those served entities, and the endpoint's traffic config. // Updates are instantaneous and endpoint should be updated instantly -func (c *internalClient) PutProvisionedThroughputInferenceEndpointConfig(ctx context.Context, req *PutPtEndpointConfigRequest, opts ...call.Option) (*PutProvisionedThroughputInferenceEndpointConfigWaiter, error) { +func (c *internalClient) PutProvisionedThroughputInferenceEndpointConfig(ctx context.Context, req PutPtEndpointConfigRequest, opts ...call.Option) (*PutProvisionedThroughputInferenceEndpointConfigWaiter, error) { if req.Name == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "Name") } @@ -1325,13 +1396,18 @@ func (c *internalClient) PutProvisionedThroughputInferenceEndpointConfig(ctx con // PutProvisionedThroughputInferenceEndpointConfigWaiter tracks the state of the operation started by PutProvisionedThroughputInferenceEndpointConfig. type PutProvisionedThroughputInferenceEndpointConfigWaiter struct { - poll func(context.Context, *GetInferenceEndpointRequest, ...call.Option) (*InferenceEndpointDetailed, error) + poll func(context.Context, GetInferenceEndpointRequest, ...call.Option) (*InferenceEndpointDetailed, error) name string } +// GetName returns the Name value used to identify the operation. +func (w *PutProvisionedThroughputInferenceEndpointConfigWaiter) GetName() string { + return w.name +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *PutProvisionedThroughputInferenceEndpointConfigWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetInferenceEndpointRequest{ + pollResp, err := w.poll(ctx, GetInferenceEndpointRequest{ Name: &w.name, }, opts...) if err != nil { @@ -1359,7 +1435,7 @@ func (w *PutProvisionedThroughputInferenceEndpointConfigWaiter) Done(ctx context func (w *PutProvisionedThroughputInferenceEndpointConfigWaiter) Wait(ctx context.Context, opts ...lro.Option) (*InferenceEndpointDetailed, error) { var result *InferenceEndpointDetailed poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetInferenceEndpointRequest{ + pollResp, err := w.poll(ctx, GetInferenceEndpointRequest{ Name: &w.name, }) if err != nil { @@ -1393,8 +1469,8 @@ func (w *PutProvisionedThroughputInferenceEndpointConfigWaiter) Wait(ctx context } // Updates the email and webhook notification settings for an endpoint. -func (c *internalClient) UpdateInferenceEndpointNotifications(ctx context.Context, req *UpdateInferenceEndpointNotificationsRequest, opts ...call.Option) (*UpdateInferenceEndpointNotificationsResponse, error) { - wireReq, err := updateInferenceEndpointNotificationsRequestToWire(req) +func (c *internalClient) UpdateInferenceEndpointNotifications(ctx context.Context, req UpdateInferenceEndpointNotificationsRequest, opts ...call.Option) (*UpdateInferenceEndpointNotificationsResponse, error) { + wireReq, err := updateInferenceEndpointNotificationsRequestToWire(&req) if err != nil { return nil, err } @@ -1415,7 +1491,11 @@ func (c *internalClient) UpdateInferenceEndpointNotifications(ctx context.Contex } pb := pathBuilder{} pb.literal("/api/2.0/serving-endpoints/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/notifications") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1463,8 +1543,8 @@ func (c *internalClient) UpdateInferenceEndpointNotifications(ctx context.Contex } // Make external services call using the credentials stored in UC Connection. -func (c *internalClient) HttpRequest(ctx context.Context, req *ExternalFunctionRequest, opts ...call.Option) (*ExternalFunctionResponse, error) { - wireReq, err := externalFunctionRequestToWire(req) +func (c *internalClient) HttpRequest(ctx context.Context, req ExternalFunctionRequest, opts ...call.Option) (*ExternalFunctionResponse, error) { + wireReq, err := externalFunctionRequestToWire(&req) if err != nil { return nil, err } diff --git a/modelserving/v1/genhelper.go b/modelserving/v1/genhelper.go old mode 100755 new mode 100644 index dc0d510..c406355 --- a/modelserving/v1/genhelper.go +++ b/modelserving/v1/genhelper.go @@ -165,11 +165,12 @@ func executeWait(ctx context.Context, operation func(context.Context) error, opt ) } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -182,13 +183,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/modelserving/v1/wire.go b/modelserving/v1/wire.go old mode 100755 new mode 100644 index ea791b1..8654694 --- a/modelserving/v1/wire.go +++ b/modelserving/v1/wire.go @@ -3,9 +3,55 @@ package modelserving import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type ai21LabsConfigWire struct { Ai21labsApiKey *string `json:"ai21labs_api_key,omitempty"` Ai21labsApiKeyPlaintext *string `json:"ai21labs_api_key_plaintext,omitempty"` @@ -106,23 +152,31 @@ func aiGatewayConfigFromWire(w *aiGatewayConfigWire) (*AiGatewayConfig, error) { } type aiGatewayRateLimitWire struct { - Calls *int64 `json:"calls,omitempty"` - Key *string `json:"key,omitempty"` - RenewalPeriod *string `json:"renewal_period,omitempty"` - Principal *string `json:"principal,omitempty"` - Tokens *int64 `json:"tokens,omitempty"` + Calls *wireInt64 `json:"calls,omitempty"` + Key *string `json:"key,omitempty"` + RenewalPeriod *string `json:"renewal_period,omitempty"` + Principal *string `json:"principal,omitempty"` + Tokens *wireInt64 `json:"tokens,omitempty"` } func aiGatewayRateLimitToWire(v *AiGatewayRateLimit) (*aiGatewayRateLimitWire, error) { if v == nil { return nil, nil } + callsWireValue, err := int64ToWire(v.Calls) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AiGatewayRateLimit.Calls", err) + } + tokensWireValue, err := int64ToWire(v.Tokens) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AiGatewayRateLimit.Tokens", err) + } return &aiGatewayRateLimitWire{ - Calls: v.Calls, + Calls: callsWireValue, Key: v.Key, RenewalPeriod: v.RenewalPeriod, Principal: v.Principal, - Tokens: v.Tokens, + Tokens: tokensWireValue, }, nil } @@ -130,12 +184,20 @@ func aiGatewayRateLimitFromWire(w *aiGatewayRateLimitWire) (*AiGatewayRateLimit, if w == nil { return nil, nil } + callsPublicValue, err := int64FromWire(w.Calls) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AiGatewayRateLimit.Calls", err) + } + tokensPublicValue, err := int64FromWire(w.Tokens) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AiGatewayRateLimit.Tokens", err) + } return &AiGatewayRateLimit{ - Calls: w.Calls, + Calls: callsPublicValue, Key: w.Key, RenewalPeriod: w.RenewalPeriod, Principal: w.Principal, - Tokens: w.Tokens, + Tokens: tokensPublicValue, }, nil } @@ -679,7 +741,7 @@ func endpointCoreConfigToWire(v *EndpointCoreConfig) (*endpointCoreConfigWire, e } type endpointCoreConfigOutputWire struct { - ConfigVersion *int64 `json:"config_version,omitempty"` + ConfigVersion *wireInt64 `json:"config_version,omitempty"` ServedEntities []servedModelWire `json:"served_entities,omitempty"` ServedModels []servedModelWire `json:"served_models,omitempty"` TrafficConfig *trafficConfigWire `json:"traffic_config,omitempty"` @@ -690,6 +752,10 @@ func endpointCoreConfigOutputFromWire(w *endpointCoreConfigOutputWire) (*Endpoin if w == nil { return nil, nil } + configVersionPublicValue, err := int64FromWire(w.ConfigVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "EndpointCoreConfigOutput.ConfigVersion", err) + } servedEntitiesPublicValue, err := convertSlice(w.ServedEntities, servedModelFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "EndpointCoreConfigOutput.ServedEntities", err) @@ -707,7 +773,7 @@ func endpointCoreConfigOutputFromWire(w *endpointCoreConfigOutputWire) (*Endpoin return nil, fmt.Errorf("%s: %w", "EndpointCoreConfigOutput.AutoCaptureConfig", err) } return &EndpointCoreConfigOutput{ - ConfigVersion: w.ConfigVersion, + ConfigVersion: configVersionPublicValue, ServedEntities: servedEntitiesPublicValue, ServedModels: servedModelsPublicValue, TrafficConfig: trafficConfigPublicValue, @@ -1122,8 +1188,8 @@ func googleCloudVertexAiConfigFromWire(w *googleCloudVertexAiConfigWire) (*Googl type inferenceEndpointWire struct { Name *string `json:"name,omitempty"` Creator *string `json:"creator,omitempty"` - CreationTimestamp *int64 `json:"creation_timestamp,omitempty"` - LastUpdatedTimestamp *int64 `json:"last_updated_timestamp,omitempty"` + CreationTimestamp *wireInt64 `json:"creation_timestamp,omitempty"` + LastUpdatedTimestamp *wireInt64 `json:"last_updated_timestamp,omitempty"` State *inferenceEndpointStateWire `json:"state,omitempty"` Config *endpointCoreConfigSummaryWire `json:"config,omitempty"` Tags []endpointTagWire `json:"tags,omitempty"` @@ -1140,6 +1206,14 @@ func inferenceEndpointFromWire(w *inferenceEndpointWire) (*InferenceEndpoint, er if w == nil { return nil, nil } + creationTimestampPublicValue, err := int64FromWire(w.CreationTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "InferenceEndpoint.CreationTimestamp", err) + } + lastUpdatedTimestampPublicValue, err := int64FromWire(w.LastUpdatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "InferenceEndpoint.LastUpdatedTimestamp", err) + } statePublicValue, err := inferenceEndpointStateFromWire(w.State) if err != nil { return nil, fmt.Errorf("%s: %w", "InferenceEndpoint.State", err) @@ -1163,8 +1237,8 @@ func inferenceEndpointFromWire(w *inferenceEndpointWire) (*InferenceEndpoint, er return &InferenceEndpoint{ Name: w.Name, Creator: w.Creator, - CreationTimestamp: w.CreationTimestamp, - LastUpdatedTimestamp: w.LastUpdatedTimestamp, + CreationTimestamp: creationTimestampPublicValue, + LastUpdatedTimestamp: lastUpdatedTimestampPublicValue, State: statePublicValue, Config: configPublicValue, Tags: tagsPublicValue, @@ -1181,8 +1255,8 @@ func inferenceEndpointFromWire(w *inferenceEndpointWire) (*InferenceEndpoint, er type inferenceEndpointDetailedWire struct { Name *string `json:"name,omitempty"` Creator *string `json:"creator,omitempty"` - CreationTimestamp *int64 `json:"creation_timestamp,omitempty"` - LastUpdatedTimestamp *int64 `json:"last_updated_timestamp,omitempty"` + CreationTimestamp *wireInt64 `json:"creation_timestamp,omitempty"` + LastUpdatedTimestamp *wireInt64 `json:"last_updated_timestamp,omitempty"` State *inferenceEndpointStateWire `json:"state,omitempty"` Config *endpointCoreConfigOutputWire `json:"config,omitempty"` PendingConfig *pendingConfigWire `json:"pending_config,omitempty"` @@ -1204,6 +1278,14 @@ func inferenceEndpointDetailedFromWire(w *inferenceEndpointDetailedWire) (*Infer if w == nil { return nil, nil } + creationTimestampPublicValue, err := int64FromWire(w.CreationTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "InferenceEndpointDetailed.CreationTimestamp", err) + } + lastUpdatedTimestampPublicValue, err := int64FromWire(w.LastUpdatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "InferenceEndpointDetailed.LastUpdatedTimestamp", err) + } statePublicValue, err := inferenceEndpointStateFromWire(w.State) if err != nil { return nil, fmt.Errorf("%s: %w", "InferenceEndpointDetailed.State", err) @@ -1239,8 +1321,8 @@ func inferenceEndpointDetailedFromWire(w *inferenceEndpointDetailedWire) (*Infer return &InferenceEndpointDetailed{ Name: w.Name, Creator: w.Creator, - CreationTimestamp: w.CreationTimestamp, - LastUpdatedTimestamp: w.LastUpdatedTimestamp, + CreationTimestamp: creationTimestampPublicValue, + LastUpdatedTimestamp: lastUpdatedTimestampPublicValue, State: statePublicValue, Config: configPublicValue, PendingConfig: pendingConfigPublicValue, @@ -1506,7 +1588,7 @@ type pendingConfigWire struct { ServedModels []servedModelWire `json:"served_models,omitempty"` TrafficConfig *trafficConfigWire `json:"traffic_config,omitempty"` ConfigVersion *int `json:"config_version,omitempty"` - StartTime *int64 `json:"start_time,omitempty"` + StartTime *wireInt64 `json:"start_time,omitempty"` AutoCaptureConfig *autoCaptureConfigWire `json:"auto_capture_config,omitempty"` } @@ -1526,6 +1608,10 @@ func pendingConfigFromWire(w *pendingConfigWire) (*PendingConfig, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "PendingConfig.TrafficConfig", err) } + startTimePublicValue, err := int64FromWire(w.StartTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PendingConfig.StartTime", err) + } autoCaptureConfigPublicValue, err := autoCaptureConfigFromWire(w.AutoCaptureConfig) if err != nil { return nil, fmt.Errorf("%s: %w", "PendingConfig.AutoCaptureConfig", err) @@ -1535,7 +1621,7 @@ func pendingConfigFromWire(w *pendingConfigWire) (*PendingConfig, error) { ServedModels: servedModelsPublicValue, TrafficConfig: trafficConfigPublicValue, ConfigVersion: w.ConfigVersion, - StartTime: w.StartTime, + StartTime: startTimePublicValue, AutoCaptureConfig: autoCaptureConfigPublicValue, }, nil } @@ -1586,22 +1672,26 @@ func ptEndpointCoreConfigToWire(v *PtEndpointCoreConfig) (*ptEndpointCoreConfigW } type ptServedModelWire struct { - Name *string `json:"name,omitempty"` - EntityName *string `json:"entity_name,omitempty"` - EntityVersion *string `json:"entity_version,omitempty"` - ProvisionedModelUnits *int64 `json:"provisioned_model_units,omitempty"` - BurstScalingEnabled *bool `json:"burst_scaling_enabled,omitempty"` + Name *string `json:"name,omitempty"` + EntityName *string `json:"entity_name,omitempty"` + EntityVersion *string `json:"entity_version,omitempty"` + ProvisionedModelUnits *wireInt64 `json:"provisioned_model_units,omitempty"` + BurstScalingEnabled *bool `json:"burst_scaling_enabled,omitempty"` } func ptServedModelToWire(v *PtServedModel) (*ptServedModelWire, error) { if v == nil { return nil, nil } + provisionedModelUnitsWireValue, err := int64ToWire(v.ProvisionedModelUnits) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PtServedModel.ProvisionedModelUnits", err) + } return &ptServedModelWire{ Name: v.Name, EntityName: v.EntityName, EntityVersion: v.EntityVersion, - ProvisionedModelUnits: v.ProvisionedModelUnits, + ProvisionedModelUnits: provisionedModelUnitsWireValue, BurstScalingEnabled: v.BurstScalingEnabled, }, nil } @@ -1783,17 +1873,21 @@ func putPtEndpointConfigRequestToWire(v *PutPtEndpointConfigRequest) (*putPtEndp } type rateLimitWire struct { - Calls *int64 `json:"calls,omitempty"` - Key *string `json:"key,omitempty"` - RenewalPeriod *string `json:"renewal_period,omitempty"` + Calls *wireInt64 `json:"calls,omitempty"` + Key *string `json:"key,omitempty"` + RenewalPeriod *string `json:"renewal_period,omitempty"` } func rateLimitToWire(v *RateLimit) (*rateLimitWire, error) { if v == nil { return nil, nil } + callsWireValue, err := int64ToWire(v.Calls) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RateLimit.Calls", err) + } return &rateLimitWire{ - Calls: v.Calls, + Calls: callsWireValue, Key: v.Key, RenewalPeriod: v.RenewalPeriod, }, nil @@ -1803,8 +1897,12 @@ func rateLimitFromWire(w *rateLimitWire) (*RateLimit, error) { if w == nil { return nil, nil } + callsPublicValue, err := int64FromWire(w.Calls) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RateLimit.Calls", err) + } return &RateLimit{ - Calls: w.Calls, + Calls: callsPublicValue, Key: w.Key, RenewalPeriod: w.RenewalPeriod, }, nil @@ -1848,7 +1946,7 @@ type servedModelWire struct { MinProvisionedConcurrency *int `json:"min_provisioned_concurrency,omitempty"` MaxProvisionedConcurrency *int `json:"max_provisioned_concurrency,omitempty"` WorkloadSize *string `json:"workload_size,omitempty"` - ProvisionedModelUnits *int64 `json:"provisioned_model_units,omitempty"` + ProvisionedModelUnits *wireInt64 `json:"provisioned_model_units,omitempty"` BurstScalingEnabled *bool `json:"burst_scaling_enabled,omitempty"` ScaleToZeroEnabled *bool `json:"scale_to_zero_enabled,omitempty"` ModelName *string `json:"model_name,omitempty"` @@ -1858,7 +1956,7 @@ type servedModelWire struct { FoundationModel *foundationModelWire `json:"foundation_model,omitempty"` State *servedModelStateWire `json:"state,omitempty"` Creator *string `json:"creator,omitempty"` - CreationTimestamp *int64 `json:"creation_timestamp,omitempty"` + CreationTimestamp *wireInt64 `json:"creation_timestamp,omitempty"` } func servedModelToWire(v *ServedModel) (*servedModelWire, error) { @@ -1869,6 +1967,10 @@ func servedModelToWire(v *ServedModel) (*servedModelWire, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "ServedModel.ExternalModel", err) } + provisionedModelUnitsWireValue, err := int64ToWire(v.ProvisionedModelUnits) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ServedModel.ProvisionedModelUnits", err) + } foundationModelWireValue, err := foundationModelToWire(v.FoundationModel) if err != nil { return nil, fmt.Errorf("%s: %w", "ServedModel.FoundationModel", err) @@ -1877,6 +1979,10 @@ func servedModelToWire(v *ServedModel) (*servedModelWire, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "ServedModel.State", err) } + creationTimestampWireValue, err := int64ToWire(v.CreationTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ServedModel.CreationTimestamp", err) + } return &servedModelWire{ Name: v.Name, ExternalModel: externalModelWireValue, @@ -1887,7 +1993,7 @@ func servedModelToWire(v *ServedModel) (*servedModelWire, error) { MinProvisionedConcurrency: v.MinProvisionedConcurrency, MaxProvisionedConcurrency: v.MaxProvisionedConcurrency, WorkloadSize: v.WorkloadSize, - ProvisionedModelUnits: v.ProvisionedModelUnits, + ProvisionedModelUnits: provisionedModelUnitsWireValue, BurstScalingEnabled: v.BurstScalingEnabled, ScaleToZeroEnabled: v.ScaleToZeroEnabled, ModelName: v.ModelName, @@ -1897,7 +2003,7 @@ func servedModelToWire(v *ServedModel) (*servedModelWire, error) { FoundationModel: foundationModelWireValue, State: stateWireValue, Creator: v.Creator, - CreationTimestamp: v.CreationTimestamp, + CreationTimestamp: creationTimestampWireValue, }, nil } @@ -1909,6 +2015,10 @@ func servedModelFromWire(w *servedModelWire) (*ServedModel, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "ServedModel.ExternalModel", err) } + provisionedModelUnitsPublicValue, err := int64FromWire(w.ProvisionedModelUnits) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ServedModel.ProvisionedModelUnits", err) + } foundationModelPublicValue, err := foundationModelFromWire(w.FoundationModel) if err != nil { return nil, fmt.Errorf("%s: %w", "ServedModel.FoundationModel", err) @@ -1917,6 +2027,10 @@ func servedModelFromWire(w *servedModelWire) (*ServedModel, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "ServedModel.State", err) } + creationTimestampPublicValue, err := int64FromWire(w.CreationTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ServedModel.CreationTimestamp", err) + } return &ServedModel{ Name: w.Name, ExternalModel: externalModelPublicValue, @@ -1927,7 +2041,7 @@ func servedModelFromWire(w *servedModelWire) (*ServedModel, error) { MinProvisionedConcurrency: w.MinProvisionedConcurrency, MaxProvisionedConcurrency: w.MaxProvisionedConcurrency, WorkloadSize: w.WorkloadSize, - ProvisionedModelUnits: w.ProvisionedModelUnits, + ProvisionedModelUnits: provisionedModelUnitsPublicValue, BurstScalingEnabled: w.BurstScalingEnabled, ScaleToZeroEnabled: w.ScaleToZeroEnabled, ModelName: w.ModelName, @@ -1937,7 +2051,7 @@ func servedModelFromWire(w *servedModelWire) (*ServedModel, error) { FoundationModel: foundationModelPublicValue, State: statePublicValue, Creator: w.Creator, - CreationTimestamp: w.CreationTimestamp, + CreationTimestamp: creationTimestampPublicValue, }, nil } diff --git a/modelservingquery/CHANGELOG.md b/modelservingquery/CHANGELOG.md index 6224c04..19f237c 100644 --- a/modelservingquery/CHANGELOG.md +++ b/modelservingquery/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/modelservingquery/go.mod b/modelservingquery/go.mod index 9409f3b..16798e6 100644 --- a/modelservingquery/go.mod +++ b/modelservingquery/go.mod @@ -9,13 +9,21 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 github.com/google/go-cmp v0.7.0 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/modelservingquery/internal/version.go b/modelservingquery/internal/version.go index 2b63526..51533c3 100644 --- a/modelservingquery/internal/version.go +++ b/modelservingquery/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-modelservingquery" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/modelservingquery/v1/client.go b/modelservingquery/v1/client.go old mode 100755 new mode 100644 index 94c33cd..2d199f0 --- a/modelservingquery/v1/client.go +++ b/modelservingquery/v1/client.go @@ -74,8 +74,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Query a serving endpoint -func (c *internalClient) Query(ctx context.Context, req *QueryEndpointRequest, opts ...call.Option) (*QueryEndpointResponse, error) { - wireReq, err := queryEndpointRequestToWire(req) +func (c *internalClient) Query(ctx context.Context, req QueryEndpointRequest, opts ...call.Option) (*QueryEndpointResponse, error) { + wireReq, err := queryEndpointRequestToWire(&req) if err != nil { return nil, err } @@ -96,7 +96,11 @@ func (c *internalClient) Query(ctx context.Context, req *QueryEndpointRequest, o } pb := pathBuilder{} pb.literal("/serving-endpoints/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/invocations") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} diff --git a/modelservingquery/v1/ext_query_dp.go b/modelservingquery/v1/ext_query_dp.go index 6e4d85b..2428a1c 100644 --- a/modelservingquery/v1/ext_query_dp.go +++ b/modelservingquery/v1/ext_query_dp.go @@ -92,7 +92,7 @@ var ErrRouteOptimizationUnavailable = errors.New("modelservingquery: route optim // Unlike Query, it never falls back to the control plane once the data-plane // call is made: an error from that call is returned as is, so a billed inference // is not silently retried elsewhere. It otherwise behaves like Query. -func (c *Client) QueryOptimized(ctx context.Context, req *QueryEndpointRequest, opts ...ops.Option) (*QueryEndpointResponse, error) { +func (c *Client) QueryOptimized(ctx context.Context, req QueryEndpointRequest, opts ...ops.Option) (*QueryEndpointResponse, error) { dp := c.dpState() if dp.cpTokens == nil || req.Name == nil { return nil, ErrRouteOptimizationUnavailable @@ -232,10 +232,10 @@ func dataPlaneInfoFromWire(w *servingEndpointDetailedWire) *dataPlaneInfo { // Query (body/response wire conversion, served-model-name header) but targets // the absolute data-plane URL and signs with the data-plane token instead of // the control-plane credentials. -func (dp *dpState) query(ctx context.Context, req *QueryEndpointRequest, ep *endpointState, opts ...ops.Option) (*QueryEndpointResponse, error) { +func (dp *dpState) query(ctx context.Context, req QueryEndpointRequest, ep *endpointState, opts ...ops.Option) (*QueryEndpointResponse, error) { c := dp.client info := ep.info - wireReq, err := queryEndpointRequestToWire(req) + wireReq, err := queryEndpointRequestToWire(&req) if err != nil { return nil, err } diff --git a/modelservingquery/v1/ext_query_dp_test.go b/modelservingquery/v1/ext_query_dp_test.go index cc01d4e..e818562 100644 --- a/modelservingquery/v1/ext_query_dp_test.go +++ b/modelservingquery/v1/ext_query_dp_test.go @@ -57,7 +57,8 @@ func newQueryTestClient(t *testing.T, server *httptest.Server, creds auth.Creden client.WithCredentials(creds), client.WithWorkspaceID("ws-123"), client.WithLogger(slog.New(slog.NewTextHandler(io.Discard, nil))), - client.WithoutProfileResolution(), + client.WithoutConfigFile(), + client.WithoutEnv(), ) if err != nil { t.Fatalf("NewClient: %v", err) @@ -250,7 +251,7 @@ func TestQueryOptimized(t *testing.T) { cl := newQueryTestClient(t, srv, tc.creds) for i := range tc.calls { - resp, gotErr := cl.QueryOptimized(context.Background(), &QueryEndpointRequest{Name: new(testEndpointName)}) + resp, gotErr := cl.QueryOptimized(context.Background(), QueryEndpointRequest{Name: new(testEndpointName)}) if tc.wantAPIError { if _, ok := errors.AsType[*apierr.APIError](gotErr); !ok { @@ -290,7 +291,7 @@ func TestQueryOptimized_DataPlaneRequest(t *testing.T) { defer srv.Close() cl := newQueryTestClient(t, srv, oauthCreds{}) - if _, err := cl.QueryOptimized(context.Background(), &QueryEndpointRequest{Name: new(testEndpointName)}); err != nil { + if _, err := cl.QueryOptimized(context.Background(), QueryEndpointRequest{Name: new(testEndpointName)}); err != nil { t.Fatalf("QueryOptimized: %v", err) } diff --git a/modelservingquery/v1/genhelper.go b/modelservingquery/v1/genhelper.go old mode 100755 new mode 100644 index f9f5942..d842026 --- a/modelservingquery/v1/genhelper.go +++ b/modelservingquery/v1/genhelper.go @@ -144,11 +144,12 @@ func executeCall(ctx context.Context, op func(context.Context) error, opts []cal return ops.Execute(ctx, op, opsOpts...) } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -161,13 +162,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/modelservingquery/v1/wire.go b/modelservingquery/v1/wire.go old mode 100755 new mode 100644 index e5672de..a2e3ab3 --- a/modelservingquery/v1/wire.go +++ b/modelservingquery/v1/wire.go @@ -3,10 +3,55 @@ package modelservingquery import ( + "bytes" "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type chatMessageWire struct { Role ChatMessageRole `json:"role,omitempty"` Content *string `json:"content,omitempty"` @@ -140,7 +185,7 @@ type queryEndpointResponseWire struct { Model *string `json:"model,omitempty"` Usage *externalModelUsageElementWire `json:"usage,omitempty"` Id *string `json:"id,omitempty"` - Created *int64 `json:"created,omitempty"` + Created *wireInt64 `json:"created,omitempty"` Object QueryEndpointResponseObject `json:"object,omitempty"` Predictions []json.RawMessage `json:"predictions,omitempty"` Outputs []json.RawMessage `json:"outputs,omitempty"` @@ -162,13 +207,17 @@ func queryEndpointResponseFromWire(w *queryEndpointResponseWire) (*QueryEndpoint if err != nil { return nil, fmt.Errorf("%s: %w", "QueryEndpointResponse.Usage", err) } + createdPublicValue, err := int64FromWire(w.Created) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryEndpointResponse.Created", err) + } return &QueryEndpointResponse{ Choices: choicesPublicValue, Data: dataPublicValue, Model: w.Model, Usage: usagePublicValue, Id: w.Id, - Created: w.Created, + Created: createdPublicValue, Object: w.Object, Predictions: w.Predictions, Outputs: w.Outputs, diff --git a/networking/CHANGELOG.md b/networking/CHANGELOG.md index 6224c04..19f237c 100644 --- a/networking/CHANGELOG.md +++ b/networking/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/networking/go.mod b/networking/go.mod index 46988f8..ec97b1c 100644 --- a/networking/go.mod +++ b/networking/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/networking/internal/version.go b/networking/internal/version.go index f625ee2..3bee0ce 100644 --- a/networking/internal/version.go +++ b/networking/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-networking" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/networking/v1/client.go b/networking/v1/client.go old mode 100755 new mode 100644 index 92dc82a..2d63264 --- a/networking/v1/client.go +++ b/networking/v1/client.go @@ -90,8 +90,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // // It can take a few minutes for the changes to take effect. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateAccountIpAccessList(ctx context.Context, req *CreateAccountIpAccessListRequest, opts ...call.Option) (*CreateAccountIpAccessListResponse, error) { - wireReq, err := createAccountIpAccessListRequestToWire(req) +func (c *internalClient) CreateAccountIpAccessList(ctx context.Context, req CreateAccountIpAccessListRequest, opts ...call.Option) (*CreateAccountIpAccessListResponse, error) { + wireReq, err := createAccountIpAccessListRequestToWire(&req) if err != nil { return nil, err } @@ -162,7 +162,7 @@ func (c *internalClient) CreateAccountIpAccessList(ctx context.Context, req *Cre // Deletes an IP access list, specified by its list ID. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteAccountIpAccessList(ctx context.Context, req *DeleteAccountIpAccessListRequest, opts ...call.Option) (*DeleteAccountIpAccessListResponse, error) { +func (c *internalClient) DeleteAccountIpAccessList(ctx context.Context, req DeleteAccountIpAccessListRequest, opts ...call.Option) (*DeleteAccountIpAccessListResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -179,7 +179,11 @@ func (c *internalClient) DeleteAccountIpAccessList(ctx context.Context, req *Del pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/ip-access-lists/") - pb.singleSegment(*req.ListId) + if req.ListId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ListId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -220,7 +224,7 @@ func (c *internalClient) DeleteAccountIpAccessList(ctx context.Context, req *Del // Gets an IP access list, specified by its list ID. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetAccountIpAccessList(ctx context.Context, req *GetAccountIpAccessListRequest, opts ...call.Option) (*GetAccountIpAccessListResponse, error) { +func (c *internalClient) GetAccountIpAccessList(ctx context.Context, req GetAccountIpAccessListRequest, opts ...call.Option) (*GetAccountIpAccessListResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -237,7 +241,11 @@ func (c *internalClient) GetAccountIpAccessList(ctx context.Context, req *GetAcc pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/ip-access-lists/") - pb.singleSegment(*req.ListId) + if req.ListId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ListId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -284,7 +292,7 @@ func (c *internalClient) GetAccountIpAccessList(ctx context.Context, req *GetAcc // Gets all IP access lists for the specified account. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListAccountIpAccessLists(ctx context.Context, req *ListAccountIpAccessListsRequest, opts ...call.Option) (*ListAccountIpAccessListsResponse, error) { +func (c *internalClient) ListAccountIpAccessLists(ctx context.Context, req ListAccountIpAccessListsRequest, opts ...call.Option) (*ListAccountIpAccessListsResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -356,8 +364,8 @@ func (c *internalClient) ListAccountIpAccessLists(ctx context.Context, req *List // the calling user's current IP, error 400 is returned with `error_code` value // `INVALID_STATE`. It can take a few minutes for the changes to take effect. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ReplaceAccountIpAccessList(ctx context.Context, req *ReplaceAccountIpAccessListRequest, opts ...call.Option) (*ReplaceAccountIpAccessListResponse, error) { - wireReq, err := replaceAccountIpAccessListRequestToWire(req) +func (c *internalClient) ReplaceAccountIpAccessList(ctx context.Context, req ReplaceAccountIpAccessListRequest, opts ...call.Option) (*ReplaceAccountIpAccessListResponse, error) { + wireReq, err := replaceAccountIpAccessListRequestToWire(&req) if err != nil { return nil, err } @@ -381,7 +389,11 @@ func (c *internalClient) ReplaceAccountIpAccessList(ctx context.Context, req *Re pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/ip-access-lists/") - pb.singleSegment(*req.ListId) + if req.ListId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ListId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -443,8 +455,8 @@ func (c *internalClient) ReplaceAccountIpAccessList(ctx context.Context, req *Re // // It can take a few minutes for the changes to take effect. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdateAccountIpAccessList(ctx context.Context, req *UpdateAccountIpAccessListRequest, opts ...call.Option) (*UpdateAccountIpAccessListResponse, error) { - wireReq, err := updateAccountIpAccessListRequestToWire(req) +func (c *internalClient) UpdateAccountIpAccessList(ctx context.Context, req UpdateAccountIpAccessListRequest, opts ...call.Option) (*UpdateAccountIpAccessListResponse, error) { + wireReq, err := updateAccountIpAccessListRequestToWire(&req) if err != nil { return nil, err } @@ -468,7 +480,11 @@ func (c *internalClient) UpdateAccountIpAccessList(ctx context.Context, req *Upd pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/ip-access-lists/") - pb.singleSegment(*req.ListId) + if req.ListId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ListId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -523,8 +539,8 @@ func (c *internalClient) UpdateAccountIpAccessList(ctx context.Context, req *Upd // state. // // An endpoint can be used only after it reaches the APPROVED state. -func (c *internalClient) CreateEndpoint(ctx context.Context, req *CreateEndpointRequest, opts ...call.Option) (*Endpoint, error) { - wireReq, err := createEndpointRequestToWire(req) +func (c *internalClient) CreateEndpoint(ctx context.Context, req CreateEndpointRequest, opts ...call.Option) (*Endpoint, error) { + wireReq, err := createEndpointRequestToWire(&req) if err != nil { return nil, err } @@ -545,7 +561,11 @@ func (c *internalClient) CreateEndpoint(ctx context.Context, req *CreateEndpoint } pb := pathBuilder{} pb.literal("/api/networking/v1/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/endpoints") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -595,7 +615,7 @@ func (c *internalClient) CreateEndpoint(ctx context.Context, req *CreateEndpoint // Deletes a network endpoint. This will remove the endpoint configuration from // . Depending on the endpoint type and use case, you may also need // to delete corresponding network resources in your cloud provider account. -func (c *internalClient) DeleteEndpoint(ctx context.Context, req *DeleteEndpointRequest, opts ...call.Option) error { +func (c *internalClient) DeleteEndpoint(ctx context.Context, req DeleteEndpointRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -609,7 +629,11 @@ func (c *internalClient) DeleteEndpoint(ctx context.Context, req *DeleteEndpoint } pb := pathBuilder{} pb.literal("/api/networking/v1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -646,7 +670,7 @@ func (c *internalClient) DeleteEndpoint(ctx context.Context, req *DeleteEndpoint } // Gets details of a specific network endpoint. -func (c *internalClient) GetEndpoint(ctx context.Context, req *GetEndpointRequest, opts ...call.Option) (*Endpoint, error) { +func (c *internalClient) GetEndpoint(ctx context.Context, req GetEndpointRequest, opts ...call.Option) (*Endpoint, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -660,7 +684,11 @@ func (c *internalClient) GetEndpoint(ctx context.Context, req *GetEndpointReques } pb := pathBuilder{} pb.literal("/api/networking/v1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -706,8 +734,8 @@ func (c *internalClient) GetEndpoint(ctx context.Context, req *GetEndpointReques } // Lists all network connectivity endpoints for the account. -func (c *internalClient) ListEndpoints(ctx context.Context, req *ListEndpointsRequest, opts ...call.Option) (*ListEndpointsResponse, error) { - wireReq, err := listEndpointsRequestToWire(req) +func (c *internalClient) ListEndpoints(ctx context.Context, req ListEndpointsRequest, opts ...call.Option) (*ListEndpointsResponse, error) { + wireReq, err := listEndpointsRequestToWire(&req) if err != nil { return nil, err } @@ -724,7 +752,11 @@ func (c *internalClient) ListEndpoints(ctx context.Context, req *ListEndpointsRe } pb := pathBuilder{} pb.literal("/api/networking/v1/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/endpoints") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -781,7 +813,7 @@ func (c *internalClient) ListEndpoints(ctx context.Context, req *ListEndpointsRe // // For example: // -// for item, err := range c.ListEndpointsIter(ctx, &ListEndpointsRequest{}) { +// for item, err := range c.ListEndpointsIter(ctx, ListEndpointsRequest{}) { // if err != nil { // return err // } @@ -793,16 +825,13 @@ func (c *internalClient) ListEndpoints(ctx context.Context, req *ListEndpointsRe // // Callers who need custom pagination logic should use // ListEndpoints directly. -func (c *internalClient) ListEndpointsIter(ctx context.Context, req *ListEndpointsRequest, opts ...call.Option) iter.Seq2[*Endpoint, error] { +func (c *internalClient) ListEndpointsIter(ctx context.Context, req ListEndpointsRequest, opts ...call.Option) iter.Seq2[*Endpoint, error] { return func(yield func(*Endpoint, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListEndpointsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListEndpoints(ctx, &pageReq, opts...) + resp, err := c.ListEndpoints(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -838,8 +867,8 @@ func (c *internalClient) ListEndpointsIter(ctx context.Context, req *ListEndpoin // [workspaceconf/setStatus] // // [workspaceconf/setStatus]: https://docs.databricks.com/api/workspace/workspaceconf/setstatus -func (c *internalClient) CreateIpAccessList(ctx context.Context, req *CreateIpAccessListRequest, opts ...call.Option) (*CreateIpAccessListResponse, error) { - wireReq, err := createIpAccessListRequestToWire(req) +func (c *internalClient) CreateIpAccessList(ctx context.Context, req CreateIpAccessListRequest, opts ...call.Option) (*CreateIpAccessListResponse, error) { + wireReq, err := createIpAccessListRequestToWire(&req) if err != nil { return nil, err } @@ -904,7 +933,7 @@ func (c *internalClient) CreateIpAccessList(ctx context.Context, req *CreateIpAc } // Deletes an IP access list, specified by its list ID. -func (c *internalClient) DeleteIpAccessList(ctx context.Context, req *DeleteIpAccessListRequest, opts ...call.Option) (*DeleteIpAccessListResponse, error) { +func (c *internalClient) DeleteIpAccessList(ctx context.Context, req DeleteIpAccessListRequest, opts ...call.Option) (*DeleteIpAccessListResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -918,7 +947,11 @@ func (c *internalClient) DeleteIpAccessList(ctx context.Context, req *DeleteIpAc } pb := pathBuilder{} pb.literal("/api/2.0/ip-access-lists/") - pb.singleSegment(*req.ListId) + if req.ListId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ListId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -958,7 +991,7 @@ func (c *internalClient) DeleteIpAccessList(ctx context.Context, req *DeleteIpAc } // Gets an IP access list, specified by its list ID. -func (c *internalClient) GetIpAccessList(ctx context.Context, req *GetIpAccessListRequest, opts ...call.Option) (*GetIpAccessListResponse, error) { +func (c *internalClient) GetIpAccessList(ctx context.Context, req GetIpAccessListRequest, opts ...call.Option) (*GetIpAccessListResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -972,7 +1005,11 @@ func (c *internalClient) GetIpAccessList(ctx context.Context, req *GetIpAccessLi } pb := pathBuilder{} pb.literal("/api/2.0/ip-access-lists/") - pb.singleSegment(*req.ListId) + if req.ListId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ListId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1018,7 +1055,7 @@ func (c *internalClient) GetIpAccessList(ctx context.Context, req *GetIpAccessLi } // Gets all IP access lists for the specified workspace. -func (c *internalClient) ListIpAccessLists(ctx context.Context, req *ListIpAccessLists, opts ...call.Option) (*ListIpAccessListsResponse, error) { +func (c *internalClient) ListIpAccessLists(ctx context.Context, req ListIpAccessLists, opts ...call.Option) (*ListIpAccessListsResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1088,8 +1125,8 @@ func (c *internalClient) ListIpAccessLists(ctx context.Context, req *ListIpAcces // feature. See [workspaceconf/setStatus]. // // [workspaceconf/setStatus]: https://docs.databricks.com/api/workspace/workspaceconf/setstatus -func (c *internalClient) ReplaceIpAccessList(ctx context.Context, req *ReplaceIpAccessListRequest, opts ...call.Option) (*ReplaceIpAccessListResponse, error) { - wireReq, err := replaceIpAccessListRequestToWire(req) +func (c *internalClient) ReplaceIpAccessList(ctx context.Context, req ReplaceIpAccessListRequest, opts ...call.Option) (*ReplaceIpAccessListResponse, error) { + wireReq, err := replaceIpAccessListRequestToWire(&req) if err != nil { return nil, err } @@ -1110,7 +1147,11 @@ func (c *internalClient) ReplaceIpAccessList(ctx context.Context, req *ReplaceIp } pb := pathBuilder{} pb.literal("/api/2.0/ip-access-lists/") - pb.singleSegment(*req.ListId) + if req.ListId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ListId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1175,8 +1216,8 @@ func (c *internalClient) ReplaceIpAccessList(ctx context.Context, req *ReplaceIp // [workspaceconf/setStatus]. // // [workspaceconf/setStatus]: https://docs.databricks.com/api/workspace/workspaceconf/setstatus -func (c *internalClient) UpdateIpAccessList(ctx context.Context, req *UpdateIpAccessListRequest, opts ...call.Option) (*UpdateIpAccessListResponse, error) { - wireReq, err := updateIpAccessListRequestToWire(req) +func (c *internalClient) UpdateIpAccessList(ctx context.Context, req UpdateIpAccessListRequest, opts ...call.Option) (*UpdateIpAccessListResponse, error) { + wireReq, err := updateIpAccessListRequestToWire(&req) if err != nil { return nil, err } @@ -1197,7 +1238,11 @@ func (c *internalClient) UpdateIpAccessList(ctx context.Context, req *UpdateIpAc } pb := pathBuilder{} pb.literal("/api/2.0/ip-access-lists/") - pb.singleSegment(*req.ListId) + if req.ListId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ListId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1257,8 +1302,8 @@ func (c *internalClient) UpdateIpAccessList(ctx context.Context, req *UpdateIpAc // // [configure serverless secure connectivity]: https://learn.microsoft.com/azure/databricks/security/network/serverless-network-security // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateNetworkConnectivityConfigPublic(ctx context.Context, req *CreateNetworkConnectivityConfigRequest, opts ...call.Option) (*NetworkConnectivityConfig, error) { - wireReq, err := createNetworkConnectivityConfigRequestToWire(req) +func (c *internalClient) CreateNetworkConnectivityConfigPublic(ctx context.Context, req CreateNetworkConnectivityConfigRequest, opts ...call.Option) (*NetworkConnectivityConfig, error) { + wireReq, err := createNetworkConnectivityConfigRequestToWire(&req) if err != nil { return nil, err } @@ -1329,7 +1374,7 @@ func (c *internalClient) CreateNetworkConnectivityConfigPublic(ctx context.Conte // Deletes a network connectivity configuration. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteNetworkConnectivityConfigPublic(ctx context.Context, req *DeleteNetworkConnectivityConfigRequest, opts ...call.Option) error { +func (c *internalClient) DeleteNetworkConnectivityConfigPublic(ctx context.Context, req DeleteNetworkConnectivityConfigRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1346,7 +1391,11 @@ func (c *internalClient) DeleteNetworkConnectivityConfigPublic(ctx context.Conte pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/network-connectivity-configs/") - pb.singleSegment(*req.NetworkConnectivityConfigId) + if req.NetworkConnectivityConfigId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NetworkConnectivityConfigId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1384,7 +1433,7 @@ func (c *internalClient) DeleteNetworkConnectivityConfigPublic(ctx context.Conte // Gets a network connectivity configuration. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetNetworkConnectivityConfigPublic(ctx context.Context, req *GetNetworkConnectivityConfigRequest, opts ...call.Option) (*NetworkConnectivityConfig, error) { +func (c *internalClient) GetNetworkConnectivityConfigPublic(ctx context.Context, req GetNetworkConnectivityConfigRequest, opts ...call.Option) (*NetworkConnectivityConfig, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1401,7 +1450,11 @@ func (c *internalClient) GetNetworkConnectivityConfigPublic(ctx context.Context, pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/network-connectivity-configs/") - pb.singleSegment(*req.NetworkConnectivityConfigId) + if req.NetworkConnectivityConfigId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NetworkConnectivityConfigId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1448,8 +1501,8 @@ func (c *internalClient) GetNetworkConnectivityConfigPublic(ctx context.Context, // Gets an array of network connectivity configurations. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListNetworkConnectivityConfigsPublic(ctx context.Context, req *ListNetworkConnectivityConfigsRequest, opts ...call.Option) (*ListNetworkConnectivityConfigsResponse, error) { - wireReq, err := listNetworkConnectivityConfigsRequestToWire(req) +func (c *internalClient) ListNetworkConnectivityConfigsPublic(ctx context.Context, req ListNetworkConnectivityConfigsRequest, opts ...call.Option) (*ListNetworkConnectivityConfigsResponse, error) { + wireReq, err := listNetworkConnectivityConfigsRequestToWire(&req) if err != nil { return nil, err } @@ -1521,7 +1574,7 @@ func (c *internalClient) ListNetworkConnectivityConfigsPublic(ctx context.Contex // // For example: // -// for item, err := range c.ListNetworkConnectivityConfigsPublicIter(ctx, &ListNetworkConnectivityConfigsRequest{}) { +// for item, err := range c.ListNetworkConnectivityConfigsPublicIter(ctx, ListNetworkConnectivityConfigsRequest{}) { // if err != nil { // return err // } @@ -1533,16 +1586,13 @@ func (c *internalClient) ListNetworkConnectivityConfigsPublic(ctx context.Contex // // Callers who need custom pagination logic should use // ListNetworkConnectivityConfigsPublic directly. -func (c *internalClient) ListNetworkConnectivityConfigsPublicIter(ctx context.Context, req *ListNetworkConnectivityConfigsRequest, opts ...call.Option) iter.Seq2[*NetworkConnectivityConfig, error] { +func (c *internalClient) ListNetworkConnectivityConfigsPublicIter(ctx context.Context, req ListNetworkConnectivityConfigsRequest, opts ...call.Option) iter.Seq2[*NetworkConnectivityConfig, error] { return func(yield func(*NetworkConnectivityConfig, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListNetworkConnectivityConfigsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListNetworkConnectivityConfigsPublic(ctx, &pageReq, opts...) + resp, err := c.ListNetworkConnectivityConfigsPublic(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1571,8 +1621,8 @@ func (c *internalClient) ListNetworkConnectivityConfigsPublicIter(ctx context.Co // // [serverless private link]: https://learn.microsoft.com/azure/databricks/security/network/serverless-network-security/serverless-private-link // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateNccPrivateEndpointRule(ctx context.Context, req *CreateNccPrivateEndpointRuleRequest, opts ...call.Option) (*NccPrivateEndpointRule, error) { - wireReq, err := createNccPrivateEndpointRuleRequestToWire(req) +func (c *internalClient) CreateNccPrivateEndpointRule(ctx context.Context, req CreateNccPrivateEndpointRuleRequest, opts ...call.Option) (*NccPrivateEndpointRule, error) { + wireReq, err := createNccPrivateEndpointRuleRequestToWire(&req) if err != nil { return nil, err } @@ -1596,7 +1646,11 @@ func (c *internalClient) CreateNccPrivateEndpointRule(ctx context.Context, req * pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/network-connectivity-configs/") - pb.singleSegment(*req.NetworkConnectivityConfigId) + if req.NetworkConnectivityConfigId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NetworkConnectivityConfigId) + } pb.literal("/private-endpoint-rules") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1650,7 +1704,7 @@ func (c *internalClient) CreateNccPrivateEndpointRule(ctx context.Context, req * // is set to `true` and the private endpoint is not available to your serverless // compute resources. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteNccPrivateEndpointRule(ctx context.Context, req *DeleteNccPrivateEndpointRuleRequest, opts ...call.Option) (*NccPrivateEndpointRule, error) { +func (c *internalClient) DeleteNccPrivateEndpointRule(ctx context.Context, req DeleteNccPrivateEndpointRuleRequest, opts ...call.Option) (*NccPrivateEndpointRule, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1667,9 +1721,17 @@ func (c *internalClient) DeleteNccPrivateEndpointRule(ctx context.Context, req * pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/network-connectivity-configs/") - pb.singleSegment(*req.NetworkConnectivityConfigId) + if req.NetworkConnectivityConfigId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NetworkConnectivityConfigId) + } pb.literal("/private-endpoint-rules/") - pb.singleSegment(*req.PrivateEndpointRuleId) + if req.PrivateEndpointRuleId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PrivateEndpointRuleId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1716,7 +1778,7 @@ func (c *internalClient) DeleteNccPrivateEndpointRule(ctx context.Context, req * // Gets the private endpoint rule. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetNccPrivateEndpointRule(ctx context.Context, req *GetNccPrivateEndpointRuleRequest, opts ...call.Option) (*NccPrivateEndpointRule, error) { +func (c *internalClient) GetNccPrivateEndpointRule(ctx context.Context, req GetNccPrivateEndpointRuleRequest, opts ...call.Option) (*NccPrivateEndpointRule, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1733,9 +1795,17 @@ func (c *internalClient) GetNccPrivateEndpointRule(ctx context.Context, req *Get pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/network-connectivity-configs/") - pb.singleSegment(*req.NetworkConnectivityConfigId) + if req.NetworkConnectivityConfigId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NetworkConnectivityConfigId) + } pb.literal("/private-endpoint-rules/") - pb.singleSegment(*req.PrivateEndpointRuleId) + if req.PrivateEndpointRuleId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PrivateEndpointRuleId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1782,8 +1852,8 @@ func (c *internalClient) GetNccPrivateEndpointRule(ctx context.Context, req *Get // Gets an array of private endpoint rules. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListNccPrivateEndpointRules(ctx context.Context, req *ListNccPrivateEndpointRulesRequest, opts ...call.Option) (*ListNccPrivateEndpointRulesResponse, error) { - wireReq, err := listNccPrivateEndpointRulesRequestToWire(req) +func (c *internalClient) ListNccPrivateEndpointRules(ctx context.Context, req ListNccPrivateEndpointRulesRequest, opts ...call.Option) (*ListNccPrivateEndpointRulesResponse, error) { + wireReq, err := listNccPrivateEndpointRulesRequestToWire(&req) if err != nil { return nil, err } @@ -1803,7 +1873,11 @@ func (c *internalClient) ListNccPrivateEndpointRules(ctx context.Context, req *L pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/network-connectivity-configs/") - pb.singleSegment(*req.NetworkConnectivityConfigId) + if req.NetworkConnectivityConfigId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NetworkConnectivityConfigId) + } pb.literal("/private-endpoint-rules") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1857,7 +1931,7 @@ func (c *internalClient) ListNccPrivateEndpointRules(ctx context.Context, req *L // // For example: // -// for item, err := range c.ListNccPrivateEndpointRulesIter(ctx, &ListNccPrivateEndpointRulesRequest{}) { +// for item, err := range c.ListNccPrivateEndpointRulesIter(ctx, ListNccPrivateEndpointRulesRequest{}) { // if err != nil { // return err // } @@ -1869,16 +1943,13 @@ func (c *internalClient) ListNccPrivateEndpointRules(ctx context.Context, req *L // // Callers who need custom pagination logic should use // ListNccPrivateEndpointRules directly. -func (c *internalClient) ListNccPrivateEndpointRulesIter(ctx context.Context, req *ListNccPrivateEndpointRulesRequest, opts ...call.Option) iter.Seq2[*NccPrivateEndpointRule, error] { +func (c *internalClient) ListNccPrivateEndpointRulesIter(ctx context.Context, req ListNccPrivateEndpointRulesRequest, opts ...call.Option) iter.Seq2[*NccPrivateEndpointRule, error] { return func(yield func(*NccPrivateEndpointRule, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListNccPrivateEndpointRulesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListNccPrivateEndpointRules(ctx, &pageReq, opts...) + resp, err := c.ListNccPrivateEndpointRules(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1899,8 +1970,8 @@ func (c *internalClient) ListNccPrivateEndpointRulesIter(ctx context.Context, re // Updates a private endpoint rule. Currently only a private endpoint rule to // customer-managed resources is allowed to be updated. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdateNccPrivateEndpointRule(ctx context.Context, req *UpdateNccPrivateEndpointRuleRequest, opts ...call.Option) (*NccPrivateEndpointRule, error) { - wireReq, err := updateNccPrivateEndpointRuleRequestToWire(req) +func (c *internalClient) UpdateNccPrivateEndpointRule(ctx context.Context, req UpdateNccPrivateEndpointRuleRequest, opts ...call.Option) (*NccPrivateEndpointRule, error) { + wireReq, err := updateNccPrivateEndpointRuleRequestToWire(&req) if err != nil { return nil, err } @@ -1924,9 +1995,17 @@ func (c *internalClient) UpdateNccPrivateEndpointRule(ctx context.Context, req * pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/network-connectivity-configs/") - pb.singleSegment(*req.NetworkConnectivityConfigId) + if req.NetworkConnectivityConfigId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NetworkConnectivityConfigId) + } pb.literal("/private-endpoint-rules/") - pb.singleSegment(*req.PrivateEndpointRuleId) + if req.PrivateEndpointRuleId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PrivateEndpointRuleId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -1978,8 +2057,8 @@ func (c *internalClient) UpdateNccPrivateEndpointRule(ctx context.Context, req * // Creates a new network policy to manage which network destinations can be // accessed from the environment. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateNetworkPolicyRpc(ctx context.Context, req *CreateNetworkPolicyRequest, opts ...call.Option) (*AccountNetworkPolicy, error) { - wireReq, err := createNetworkPolicyRequestToWire(req) +func (c *internalClient) CreateNetworkPolicyRpc(ctx context.Context, req CreateNetworkPolicyRequest, opts ...call.Option) (*AccountNetworkPolicy, error) { + wireReq, err := createNetworkPolicyRequestToWire(&req) if err != nil { return nil, err } @@ -2050,7 +2129,7 @@ func (c *internalClient) CreateNetworkPolicyRpc(ctx context.Context, req *Create // Deletes a network policy. Cannot be called on 'default-policy'. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteNetworkPolicyRpc(ctx context.Context, req *DeleteNetworkPolicyRequest, opts ...call.Option) error { +func (c *internalClient) DeleteNetworkPolicyRpc(ctx context.Context, req DeleteNetworkPolicyRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2067,7 +2146,11 @@ func (c *internalClient) DeleteNetworkPolicyRpc(ctx context.Context, req *Delete pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/network-policies/") - pb.singleSegment(*req.NetworkPolicyId) + if req.NetworkPolicyId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NetworkPolicyId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2105,7 +2188,7 @@ func (c *internalClient) DeleteNetworkPolicyRpc(ctx context.Context, req *Delete // Gets a network policy. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetNetworkPolicyRpc(ctx context.Context, req *GetNetworkPolicyRequest, opts ...call.Option) (*AccountNetworkPolicy, error) { +func (c *internalClient) GetNetworkPolicyRpc(ctx context.Context, req GetNetworkPolicyRequest, opts ...call.Option) (*AccountNetworkPolicy, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2122,7 +2205,11 @@ func (c *internalClient) GetNetworkPolicyRpc(ctx context.Context, req *GetNetwor pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/network-policies/") - pb.singleSegment(*req.NetworkPolicyId) + if req.NetworkPolicyId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NetworkPolicyId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2169,8 +2256,8 @@ func (c *internalClient) GetNetworkPolicyRpc(ctx context.Context, req *GetNetwor // Gets an array of network policies. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListNetworkPoliciesRpc(ctx context.Context, req *ListNetworkPoliciesRequest, opts ...call.Option) (*ListNetworkPoliciesResponse, error) { - wireReq, err := listNetworkPoliciesRequestToWire(req) +func (c *internalClient) ListNetworkPoliciesRpc(ctx context.Context, req ListNetworkPoliciesRequest, opts ...call.Option) (*ListNetworkPoliciesResponse, error) { + wireReq, err := listNetworkPoliciesRequestToWire(&req) if err != nil { return nil, err } @@ -2242,7 +2329,7 @@ func (c *internalClient) ListNetworkPoliciesRpc(ctx context.Context, req *ListNe // // For example: // -// for item, err := range c.ListNetworkPoliciesRpcIter(ctx, &ListNetworkPoliciesRequest{}) { +// for item, err := range c.ListNetworkPoliciesRpcIter(ctx, ListNetworkPoliciesRequest{}) { // if err != nil { // return err // } @@ -2254,16 +2341,13 @@ func (c *internalClient) ListNetworkPoliciesRpc(ctx context.Context, req *ListNe // // Callers who need custom pagination logic should use // ListNetworkPoliciesRpc directly. -func (c *internalClient) ListNetworkPoliciesRpcIter(ctx context.Context, req *ListNetworkPoliciesRequest, opts ...call.Option) iter.Seq2[*AccountNetworkPolicy, error] { +func (c *internalClient) ListNetworkPoliciesRpcIter(ctx context.Context, req ListNetworkPoliciesRequest, opts ...call.Option) iter.Seq2[*AccountNetworkPolicy, error] { return func(yield func(*AccountNetworkPolicy, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListNetworkPoliciesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListNetworkPoliciesRpc(ctx, &pageReq, opts...) + resp, err := c.ListNetworkPoliciesRpc(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -2284,8 +2368,8 @@ func (c *internalClient) ListNetworkPoliciesRpcIter(ctx context.Context, req *Li // Updates a network policy. This allows you to modify the configuration of a // network policy. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdateNetworkPolicyRpc(ctx context.Context, req *UpdateNetworkPolicyRequest, opts ...call.Option) (*AccountNetworkPolicy, error) { - wireReq, err := updateNetworkPolicyRequestToWire(req) +func (c *internalClient) UpdateNetworkPolicyRpc(ctx context.Context, req UpdateNetworkPolicyRequest, opts ...call.Option) (*AccountNetworkPolicy, error) { + wireReq, err := updateNetworkPolicyRequestToWire(&req) if err != nil { return nil, err } @@ -2309,7 +2393,11 @@ func (c *internalClient) UpdateNetworkPolicyRpc(ctx context.Context, req *Update pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/network-policies/") - pb.singleSegment(*req.NetworkPolicyId) + if req.NetworkPolicyId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NetworkPolicyId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2359,8 +2447,8 @@ func (c *internalClient) UpdateNetworkPolicyRpc(ctx context.Context, req *Update // resources. The VPC will be used for new clusters. This requires // a pre-existing VPC and subnets. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateNetworkPublic(ctx context.Context, req *CreateNetworkRequest, opts ...call.Option) (*Network, error) { - wireReq, err := createNetworkRequestToWire(req) +func (c *internalClient) CreateNetworkPublic(ctx context.Context, req CreateNetworkRequest, opts ...call.Option) (*Network, error) { + wireReq, err := createNetworkRequestToWire(&req) if err != nil { return nil, err } @@ -2434,8 +2522,8 @@ func (c *internalClient) CreateNetworkPublic(ctx context.Context, req *CreateNet // configure whether workspaces can be accessed from the public internet or only // from private endpoints. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreatePrivateAccessSettingsPublic(ctx context.Context, req *CreatePrivateAccessSettingsRequest, opts ...call.Option) (*PrivateAccessSettings, error) { - wireReq, err := createPrivateAccessSettingsRequestToWire(req) +func (c *internalClient) CreatePrivateAccessSettingsPublic(ctx context.Context, req CreatePrivateAccessSettingsRequest, opts ...call.Option) (*PrivateAccessSettings, error) { + wireReq, err := createPrivateAccessSettingsRequestToWire(&req) if err != nil { return nil, err } @@ -2519,8 +2607,8 @@ func (c *internalClient) CreatePrivateAccessSettingsPublic(ctx context.Context, // [VPC endpoint]: https://docs.aws.amazon.com/vpc/latest/privatelink/vpc-endpoints.html // [endpoint service]: https://docs.aws.amazon.com/vpc/latest/privatelink/privatelink-share-your-services.html // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateVpcEndpointPublic(ctx context.Context, req *CreateVpcEndpointRequest, opts ...call.Option) (*VpcEndpoint, error) { - wireReq, err := createVpcEndpointRequestToWire(req) +func (c *internalClient) CreateVpcEndpointPublic(ctx context.Context, req CreateVpcEndpointRequest, opts ...call.Option) (*VpcEndpoint, error) { + wireReq, err := createVpcEndpointRequestToWire(&req) if err != nil { return nil, err } @@ -2596,7 +2684,7 @@ func (c *internalClient) CreateVpcEndpointPublic(ctx context.Context, req *Creat // This operation is available only if your account is on the E2 version of the // platform. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteNetworkPublic(ctx context.Context, req *DeleteNetworkRequest, opts ...call.Option) (*Network, error) { +func (c *internalClient) DeleteNetworkPublic(ctx context.Context, req DeleteNetworkRequest, opts ...call.Option) (*Network, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2613,7 +2701,11 @@ func (c *internalClient) DeleteNetworkPublic(ctx context.Context, req *DeleteNet pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/networks/") - pb.singleSegment(*req.NetworkId) + if req.NetworkId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NetworkId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2661,7 +2753,7 @@ func (c *internalClient) DeleteNetworkPublic(ctx context.Context, req *DeleteNet // Deletes a private access settings configuration, both specified // by ID. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeletePrivateAccessSettingsPublic(ctx context.Context, req *DeletePrivateAccessSettingsRequest, opts ...call.Option) (*PrivateAccessSettings, error) { +func (c *internalClient) DeletePrivateAccessSettingsPublic(ctx context.Context, req DeletePrivateAccessSettingsRequest, opts ...call.Option) (*PrivateAccessSettings, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2678,7 +2770,11 @@ func (c *internalClient) DeletePrivateAccessSettingsPublic(ctx context.Context, pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/private-access-settings/") - pb.singleSegment(*req.PrivateAccessSettingsId) + if req.PrivateAccessSettingsId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PrivateAccessSettingsId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2726,7 +2822,7 @@ func (c *internalClient) DeletePrivateAccessSettingsPublic(ctx context.Context, // Deletes a Databricks VPC endpoint configuration. You cannot delete a VPC // endpoint configuration that is associated with any workspace. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteVpcEndpointPublic(ctx context.Context, req *DeleteVpcEndpointRequest, opts ...call.Option) (*VpcEndpoint, error) { +func (c *internalClient) DeleteVpcEndpointPublic(ctx context.Context, req DeleteVpcEndpointRequest, opts ...call.Option) (*VpcEndpoint, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2743,7 +2839,11 @@ func (c *internalClient) DeleteVpcEndpointPublic(ctx context.Context, req *Delet pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/vpc-endpoints/") - pb.singleSegment(*req.VpcEndpointId) + if req.VpcEndpointId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.VpcEndpointId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2791,7 +2891,7 @@ func (c *internalClient) DeleteVpcEndpointPublic(ctx context.Context, req *Delet // Gets a network configuration, which represents a cloud VPC and // its resources. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetNetworkPublic(ctx context.Context, req *GetNetworkRequest, opts ...call.Option) (*Network, error) { +func (c *internalClient) GetNetworkPublic(ctx context.Context, req GetNetworkRequest, opts ...call.Option) (*Network, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2808,7 +2908,11 @@ func (c *internalClient) GetNetworkPublic(ctx context.Context, req *GetNetworkRe pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/networks/") - pb.singleSegment(*req.NetworkId) + if req.NetworkId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NetworkId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2856,7 +2960,7 @@ func (c *internalClient) GetNetworkPublic(ctx context.Context, req *GetNetworkRe // Gets a private access settings configuration, both specified by // ID. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetPrivateAccessSettingsPublic(ctx context.Context, req *GetPrivateAccessSettingsRequest, opts ...call.Option) (*PrivateAccessSettings, error) { +func (c *internalClient) GetPrivateAccessSettingsPublic(ctx context.Context, req GetPrivateAccessSettingsRequest, opts ...call.Option) (*PrivateAccessSettings, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2873,7 +2977,11 @@ func (c *internalClient) GetPrivateAccessSettingsPublic(ctx context.Context, req pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/private-access-settings/") - pb.singleSegment(*req.PrivateAccessSettingsId) + if req.PrivateAccessSettingsId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PrivateAccessSettingsId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2925,7 +3033,7 @@ func (c *internalClient) GetPrivateAccessSettingsPublic(ctx context.Context, req // [AWS PrivateLink]: https://aws.amazon.com/privatelink // [VPC endpoint]: https://docs.aws.amazon.com/vpc/latest/privatelink/concepts.html // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetVpcEndpointPublic(ctx context.Context, req *GetVpcEndpointRequest, opts ...call.Option) (*VpcEndpoint, error) { +func (c *internalClient) GetVpcEndpointPublic(ctx context.Context, req GetVpcEndpointRequest, opts ...call.Option) (*VpcEndpoint, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2942,7 +3050,11 @@ func (c *internalClient) GetVpcEndpointPublic(ctx context.Context, req *GetVpcEn pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/vpc-endpoints/") - pb.singleSegment(*req.VpcEndpointId) + if req.VpcEndpointId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.VpcEndpointId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2989,7 +3101,7 @@ func (c *internalClient) GetVpcEndpointPublic(ctx context.Context, req *GetVpcEn // Lists network configurations for an account. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListNetworkPublic(ctx context.Context, req *ListNetworkRequest, opts ...call.Option) (*ListNetworkResponse, error) { +func (c *internalClient) ListNetworkPublic(ctx context.Context, req ListNetworkRequest, opts ...call.Option) (*ListNetworkResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -3055,7 +3167,7 @@ func (c *internalClient) ListNetworkPublic(ctx context.Context, req *ListNetwork // Lists private access settings for an account. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListPrivateAccessSettingsPublic(ctx context.Context, req *ListPrivateAccessSettingsRequest, opts ...call.Option) (*ListPrivateAccessSettingsResponse, error) { +func (c *internalClient) ListPrivateAccessSettingsPublic(ctx context.Context, req ListPrivateAccessSettingsRequest, opts ...call.Option) (*ListPrivateAccessSettingsResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -3121,7 +3233,7 @@ func (c *internalClient) ListPrivateAccessSettingsPublic(ctx context.Context, re // Lists Databricks VPC endpoint configurations for an account. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListVpcEndpointPublic(ctx context.Context, req *ListVpcEndpointRequest, opts ...call.Option) (*ListVpcEndpointResponse, error) { +func (c *internalClient) ListVpcEndpointPublic(ctx context.Context, req ListVpcEndpointRequest, opts ...call.Option) (*ListVpcEndpointResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -3199,8 +3311,8 @@ func (c *internalClient) ListVpcEndpointPublic(ctx context.Context, req *ListVpc // the same AWS region can use a given private access settings object. Before // configuring PrivateLink, read the article about PrivateLink. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdatePrivateAccessSettingsPublic(ctx context.Context, req *UpdatePrivateAccessSettingsRequest, opts ...call.Option) (*PrivateAccessSettings, error) { - wireReq, err := updatePrivateAccessSettingsRequestToWire(req) +func (c *internalClient) UpdatePrivateAccessSettingsPublic(ctx context.Context, req UpdatePrivateAccessSettingsRequest, opts ...call.Option) (*PrivateAccessSettings, error) { + wireReq, err := updatePrivateAccessSettingsRequestToWire(&req) if err != nil { return nil, err } @@ -3221,7 +3333,11 @@ func (c *internalClient) UpdatePrivateAccessSettingsPublic(ctx context.Context, pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/private-access-settings/") - pb.singleSegment(*req.CustomerFacingPrivateAccessSettings.PrivateAccessSettingsId) + if req.CustomerFacingPrivateAccessSettings == nil || req.CustomerFacingPrivateAccessSettings.PrivateAccessSettingsId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CustomerFacingPrivateAccessSettings.PrivateAccessSettingsId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -3271,7 +3387,7 @@ func (c *internalClient) UpdatePrivateAccessSettingsPublic(ctx context.Context, // network policy binding, with 'default-policy' used if no explicit assignment // exists. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetWorkspaceNetworkOptionRpc(ctx context.Context, req *GetWorkspaceNetworkOptionRequest, opts ...call.Option) (*WorkspaceNetworkOption, error) { +func (c *internalClient) GetWorkspaceNetworkOptionRpc(ctx context.Context, req GetWorkspaceNetworkOptionRequest, opts ...call.Option) (*WorkspaceNetworkOption, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -3288,7 +3404,11 @@ func (c *internalClient) GetWorkspaceNetworkOptionRpc(ctx context.Context, req * pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/workspaces/") - pb.singleSegment(*req.WorkspaceId) + if req.WorkspaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.WorkspaceId) + } pb.literal("/network") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -3338,8 +3458,8 @@ func (c *internalClient) GetWorkspaceNetworkOptionRpc(ctx context.Context, req * // workspace with the specified network policy. To revert to the default policy, // specify 'default-policy' as the network_policy_id. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdateWorkspaceNetworkOptionRpc(ctx context.Context, req *UpdateWorkspaceNetworkOptionRequest, opts ...call.Option) (*WorkspaceNetworkOption, error) { - wireReq, err := updateWorkspaceNetworkOptionRequestToWire(req) +func (c *internalClient) UpdateWorkspaceNetworkOptionRpc(ctx context.Context, req UpdateWorkspaceNetworkOptionRequest, opts ...call.Option) (*WorkspaceNetworkOption, error) { + wireReq, err := updateWorkspaceNetworkOptionRequestToWire(&req) if err != nil { return nil, err } @@ -3363,7 +3483,11 @@ func (c *internalClient) UpdateWorkspaceNetworkOptionRpc(ctx context.Context, re pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/workspaces/") - pb.singleSegment(*req.WorkspaceId) + if req.WorkspaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.WorkspaceId) + } pb.literal("/network") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} diff --git a/networking/v1/genhelper.go b/networking/v1/genhelper.go old mode 100755 new mode 100644 index 3aadb38..4d5899e --- a/networking/v1/genhelper.go +++ b/networking/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/networking/v1/model.go b/networking/v1/model.go old mode 100755 new mode 100644 index 438d17b..34e9e0f --- a/networking/v1/model.go +++ b/networking/v1/model.go @@ -190,11 +190,21 @@ const ( IngressNetworkPolicy_AuthenticationIdentity_PrincipalType_PrincipalTypeServicePrincipal IngressNetworkPolicy_AuthenticationIdentity_PrincipalType = "PRINCIPAL_TYPE_SERVICE_PRINCIPAL" ) +// The restriction mode for cross-workspace access. In FULL_ACCESS mode, +// requests from any source workspace (in any account) are allowed, and deny +// rules and allow rules cannot be set. In RESTRICTED_ACCESS mode, access is +// restricted based on deny rules and allow rules; requests that do not match +// any allow rule are denied. In LEGACY_MODE, cross-workspace ingress is not +// governed by this policy. type IngressNetworkPolicy_CrossWorkspaceAccess_RestrictionMode string const ( - IngressNetworkPolicy_CrossWorkspaceAccess_RestrictionMode_Unspecified IngressNetworkPolicy_CrossWorkspaceAccess_RestrictionMode = "" - IngressNetworkPolicy_CrossWorkspaceAccess_RestrictionMode_FullAccess IngressNetworkPolicy_CrossWorkspaceAccess_RestrictionMode = "FULL_ACCESS" + IngressNetworkPolicy_CrossWorkspaceAccess_RestrictionMode_Unspecified IngressNetworkPolicy_CrossWorkspaceAccess_RestrictionMode = "" + // Allows requests from any source workspace, regardless of account. Deny rules + // and allow rules cannot be set in this mode. + IngressNetworkPolicy_CrossWorkspaceAccess_RestrictionMode_FullAccess IngressNetworkPolicy_CrossWorkspaceAccess_RestrictionMode = "FULL_ACCESS" + // Restricts access based on deny rules and allow rules. Requests that do not + // match any allow rule are denied. IngressNetworkPolicy_CrossWorkspaceAccess_RestrictionMode_RestrictedAccess IngressNetworkPolicy_CrossWorkspaceAccess_RestrictionMode = "RESTRICTED_ACCESS" // Cross-workspace ingress is not governed by this policy. Traffic from other // workspaces is subject only to the workspace's pre-existing network controls, @@ -1038,14 +1048,30 @@ type IngressNetworkPolicy_AuthenticationIdentity struct { } type IngressNetworkPolicy_CrossWorkspaceAccess struct { + // The restriction mode for cross-workspace access. RestrictionMode IngressNetworkPolicy_CrossWorkspaceAccess_RestrictionMode - DenyRules []IngressNetworkPolicy_CrossWorkspaceIngressRule - AllowRules []IngressNetworkPolicy_CrossWorkspaceIngressRule + // Deny rules are evaluated first. A request matching any deny rule is denied, + // regardless of allow rules. Only applies when restriction_mode is + // RESTRICTED_ACCESS. + DenyRules []IngressNetworkPolicy_CrossWorkspaceIngressRule + // Allow rules are evaluated after deny rules. A request matching any allow rule + // is allowed; a request matching no rule is denied by default. Only applies + // when restriction_mode is RESTRICTED_ACCESS. + AllowRules []IngressNetworkPolicy_CrossWorkspaceIngressRule } +// An ingress rule is enforced when a request satisfies all specified attributes +// — including request origin, destination, and authentication.. type IngressNetworkPolicy_CrossWorkspaceIngressRule struct { - Origin *IngressNetworkPolicy_CrossWorkspaceRequestOrigin - Destination *IngressNetworkPolicy_RequestDestination + // The origin the request must match — the source workspace the request comes + // from, either specific source workspaces or any source workspace in any + // account. See CrossWorkspaceRequestOrigin. + Origin *IngressNetworkPolicy_CrossWorkspaceRequestOrigin + // The destination the request must match — the resource being accessed, for + // example the workspace UI or workspace APIs. See RequestDestination. + Destination *IngressNetworkPolicy_RequestDestination + // The authenticated identity the request must match. When unset, the rule + // matches all users and service principals. Authentication *IngressNetworkPolicy_Authentication // The label for this ingress rule. Label *string diff --git a/networking/v1/wire.go b/networking/v1/wire.go old mode 100755 new mode 100644 index ca0aefc..8a01eb5 --- a/networking/v1/wire.go +++ b/networking/v1/wire.go @@ -3,11 +3,57 @@ package networking import ( + "bytes" + "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + func fieldMaskToWire[T any](mask *types.FieldMask[T]) *string { if mask == nil { return nil @@ -22,10 +68,10 @@ type accountIpAccessListWire struct { IpAddresses []string `json:"ip_addresses,omitempty"` AddressCount *int `json:"address_count,omitempty"` ListType AccountIpAccessListType_IpAccessListType `json:"list_type,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` - CreatedBy *int64 `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` - UpdatedBy *int64 `json:"updated_by,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` + CreatedBy *wireInt64 `json:"created_by,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` + UpdatedBy *wireInt64 `json:"updated_by,omitempty"` Enabled *bool `json:"enabled,omitempty"` } @@ -33,16 +79,32 @@ func accountIpAccessListFromWire(w *accountIpAccessListWire) (*AccountIpAccessLi if w == nil { return nil, nil } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AccountIpAccessList.CreatedAt", err) + } + createdByPublicValue, err := int64FromWire(w.CreatedBy) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AccountIpAccessList.CreatedBy", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AccountIpAccessList.UpdatedAt", err) + } + updatedByPublicValue, err := int64FromWire(w.UpdatedBy) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AccountIpAccessList.UpdatedBy", err) + } return &AccountIpAccessList{ ListId: w.ListId, Label: w.Label, IpAddresses: w.IpAddresses, AddressCount: w.AddressCount, ListType: w.ListType, - CreatedAt: w.CreatedAt, - CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, - UpdatedBy: w.UpdatedBy, + CreatedAt: createdAtPublicValue, + CreatedBy: createdByPublicValue, + UpdatedAt: updatedAtPublicValue, + UpdatedBy: updatedByPublicValue, Enabled: w.Enabled, }, nil } @@ -299,8 +361,8 @@ type createNetworkConnectivityConfigurationWire struct { Name *string `json:"name,omitempty"` Region *string `json:"region,omitempty"` EgressConfig *customerFacingNetworkConnectivityConfigEgressConfigWire `json:"egress_config,omitempty"` - UpdatedTime *int64 `json:"updated_time,omitempty"` - CreationTime *int64 `json:"creation_time,omitempty"` + UpdatedTime *wireInt64 `json:"updated_time,omitempty"` + CreationTime *wireInt64 `json:"creation_time,omitempty"` } func createNetworkConnectivityConfigurationToWire(v *CreateNetworkConnectivityConfiguration) (*createNetworkConnectivityConfigurationWire, error) { @@ -311,14 +373,22 @@ func createNetworkConnectivityConfigurationToWire(v *CreateNetworkConnectivityCo if err != nil { return nil, fmt.Errorf("%s: %w", "CreateNetworkConnectivityConfiguration.EgressConfig", err) } + updatedTimeWireValue, err := int64ToWire(v.UpdatedTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateNetworkConnectivityConfiguration.UpdatedTime", err) + } + creationTimeWireValue, err := int64ToWire(v.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateNetworkConnectivityConfiguration.CreationTime", err) + } return &createNetworkConnectivityConfigurationWire{ NetworkConnectivityConfigId: v.NetworkConnectivityConfigId, AccountId: v.AccountId, Name: v.Name, Region: v.Region, EgressConfig: egressConfigWireValue, - UpdatedTime: v.UpdatedTime, - CreationTime: v.CreationTime, + UpdatedTime: updatedTimeWireValue, + CreationTime: creationTimeWireValue, }, nil } @@ -402,10 +472,10 @@ type createPrivateEndpointRuleWire struct { NetworkConnectivityConfigId *string `json:"network_connectivity_config_id,omitempty"` ConnectionState NccPrivateEndpointRule_PrivateLinkConnectionState `json:"connection_state,omitempty"` DomainNames []string `json:"domain_names,omitempty"` - CreationTime *int64 `json:"creation_time,omitempty"` - UpdatedTime *int64 `json:"updated_time,omitempty"` + CreationTime *wireInt64 `json:"creation_time,omitempty"` + UpdatedTime *wireInt64 `json:"updated_time,omitempty"` Deactivated *bool `json:"deactivated,omitempty"` - DeactivatedAt *int64 `json:"deactivated_at,omitempty"` + DeactivatedAt *wireInt64 `json:"deactivated_at,omitempty"` ErrorMessage *string `json:"error_message,omitempty"` ResourceId *string `json:"resource_id,omitempty"` GroupId *string `json:"group_id,omitempty"` @@ -422,6 +492,18 @@ func createPrivateEndpointRuleToWire(v *CreatePrivateEndpointRule) (*createPriva if v == nil { return nil, nil } + creationTimeWireValue, err := int64ToWire(v.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreatePrivateEndpointRule.CreationTime", err) + } + updatedTimeWireValue, err := int64ToWire(v.UpdatedTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreatePrivateEndpointRule.UpdatedTime", err) + } + deactivatedAtWireValue, err := int64ToWire(v.DeactivatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreatePrivateEndpointRule.DeactivatedAt", err) + } var endpointGcpEndpointWire *gcpEndpointWire switch value := v.Endpoint.(type) { case nil: @@ -441,10 +523,10 @@ func createPrivateEndpointRuleToWire(v *CreatePrivateEndpointRule) (*createPriva NetworkConnectivityConfigId: v.NetworkConnectivityConfigId, ConnectionState: v.ConnectionState, DomainNames: v.DomainNames, - CreationTime: v.CreationTime, - UpdatedTime: v.UpdatedTime, + CreationTime: creationTimeWireValue, + UpdatedTime: updatedTimeWireValue, Deactivated: v.Deactivated, - DeactivatedAt: v.DeactivatedAt, + DeactivatedAt: deactivatedAtWireValue, ErrorMessage: v.ErrorMessage, ResourceId: v.ResourceId, GroupId: v.GroupId, @@ -683,15 +765,19 @@ func egressNetworkPolicy_NetworkAccessPolicyFromWire(w *egressNetworkPolicy_Netw } type egressNetworkPolicy_NetworkAccessPolicy_DatabricksDestinationWire struct { - WorkspaceIds []int64 `json:"workspace_ids,omitempty"` + WorkspaceIds []wireInt64 `json:"workspace_ids,omitempty"` } func egressNetworkPolicy_NetworkAccessPolicy_DatabricksDestinationToWire(v *EgressNetworkPolicy_NetworkAccessPolicy_DatabricksDestination) (*egressNetworkPolicy_NetworkAccessPolicy_DatabricksDestinationWire, error) { if v == nil { return nil, nil } + workspaceIdsWireValue, err := convertSlice(v.WorkspaceIds, int64ToWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "EgressNetworkPolicy_NetworkAccessPolicy_DatabricksDestination.WorkspaceIds", err) + } return &egressNetworkPolicy_NetworkAccessPolicy_DatabricksDestinationWire{ - WorkspaceIds: v.WorkspaceIds, + WorkspaceIds: workspaceIdsWireValue, }, nil } @@ -699,8 +785,12 @@ func egressNetworkPolicy_NetworkAccessPolicy_DatabricksDestinationFromWire(w *eg if w == nil { return nil, nil } + workspaceIdsPublicValue, err := convertSlice(w.WorkspaceIds, int64FromWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "EgressNetworkPolicy_NetworkAccessPolicy_DatabricksDestination.WorkspaceIds", err) + } return &EgressNetworkPolicy_NetworkAccessPolicy_DatabricksDestination{ - WorkspaceIds: w.WorkspaceIds, + WorkspaceIds: workspaceIdsPublicValue, }, nil } @@ -1322,16 +1412,20 @@ func ingressNetworkPolicy_AuthenticationFromWire(w *ingressNetworkPolicy_Authent type ingressNetworkPolicy_AuthenticationIdentityWire struct { PrincipalType IngressNetworkPolicy_AuthenticationIdentity_PrincipalType `json:"principal_type,omitempty"` - PrincipalId *int64 `json:"principal_id,omitempty"` + PrincipalId *wireInt64 `json:"principal_id,omitempty"` } func ingressNetworkPolicy_AuthenticationIdentityToWire(v *IngressNetworkPolicy_AuthenticationIdentity) (*ingressNetworkPolicy_AuthenticationIdentityWire, error) { if v == nil { return nil, nil } + principalIdWireValue, err := int64ToWire(v.PrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "IngressNetworkPolicy_AuthenticationIdentity.PrincipalId", err) + } return &ingressNetworkPolicy_AuthenticationIdentityWire{ PrincipalType: v.PrincipalType, - PrincipalId: v.PrincipalId, + PrincipalId: principalIdWireValue, }, nil } @@ -1339,9 +1433,13 @@ func ingressNetworkPolicy_AuthenticationIdentityFromWire(w *ingressNetworkPolicy if w == nil { return nil, nil } + principalIdPublicValue, err := int64FromWire(w.PrincipalId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "IngressNetworkPolicy_AuthenticationIdentity.PrincipalId", err) + } return &IngressNetworkPolicy_AuthenticationIdentity{ PrincipalType: w.PrincipalType, - PrincipalId: w.PrincipalId, + PrincipalId: principalIdPublicValue, }, nil } @@ -2069,15 +2167,19 @@ func ingressNetworkPolicy_WorkspaceApiDestinationFromWire(w *ingressNetworkPolic } type ingressNetworkPolicy_WorkspaceIdListWire struct { - WorkspaceIds []int64 `json:"workspace_ids,omitempty"` + WorkspaceIds []wireInt64 `json:"workspace_ids,omitempty"` } func ingressNetworkPolicy_WorkspaceIdListToWire(v *IngressNetworkPolicy_WorkspaceIdList) (*ingressNetworkPolicy_WorkspaceIdListWire, error) { if v == nil { return nil, nil } + workspaceIdsWireValue, err := convertSlice(v.WorkspaceIds, int64ToWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "IngressNetworkPolicy_WorkspaceIdList.WorkspaceIds", err) + } return &ingressNetworkPolicy_WorkspaceIdListWire{ - WorkspaceIds: v.WorkspaceIds, + WorkspaceIds: workspaceIdsWireValue, }, nil } @@ -2085,8 +2187,12 @@ func ingressNetworkPolicy_WorkspaceIdListFromWire(w *ingressNetworkPolicy_Worksp if w == nil { return nil, nil } + workspaceIdsPublicValue, err := convertSlice(w.WorkspaceIds, int64FromWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "IngressNetworkPolicy_WorkspaceIdList.WorkspaceIds", err) + } return &IngressNetworkPolicy_WorkspaceIdList{ - WorkspaceIds: w.WorkspaceIds, + WorkspaceIds: workspaceIdsPublicValue, }, nil } @@ -2118,10 +2224,10 @@ type ipAccessListWire struct { IpAddresses []string `json:"ip_addresses,omitempty"` AddressCount *int `json:"address_count,omitempty"` ListType IpAccessListType `json:"list_type,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` - CreatedBy *int64 `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` - UpdatedBy *int64 `json:"updated_by,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` + CreatedBy *wireInt64 `json:"created_by,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` + UpdatedBy *wireInt64 `json:"updated_by,omitempty"` Enabled *bool `json:"enabled,omitempty"` } @@ -2129,16 +2235,32 @@ func ipAccessListFromWire(w *ipAccessListWire) (*IpAccessList, error) { if w == nil { return nil, nil } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "IpAccessList.CreatedAt", err) + } + createdByPublicValue, err := int64FromWire(w.CreatedBy) + if err != nil { + return nil, fmt.Errorf("%s: %w", "IpAccessList.CreatedBy", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "IpAccessList.UpdatedAt", err) + } + updatedByPublicValue, err := int64FromWire(w.UpdatedBy) + if err != nil { + return nil, fmt.Errorf("%s: %w", "IpAccessList.UpdatedBy", err) + } return &IpAccessList{ ListId: w.ListId, Label: w.Label, IpAddresses: w.IpAddresses, AddressCount: w.AddressCount, ListType: w.ListType, - CreatedAt: w.CreatedAt, - CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, - UpdatedBy: w.UpdatedBy, + CreatedAt: createdAtPublicValue, + CreatedBy: createdByPublicValue, + UpdatedAt: updatedAtPublicValue, + UpdatedBy: updatedByPublicValue, Enabled: w.Enabled, }, nil } @@ -2322,10 +2444,10 @@ type nccPrivateEndpointRuleWire struct { NetworkConnectivityConfigId *string `json:"network_connectivity_config_id,omitempty"` ConnectionState NccPrivateEndpointRule_PrivateLinkConnectionState `json:"connection_state,omitempty"` DomainNames []string `json:"domain_names,omitempty"` - CreationTime *int64 `json:"creation_time,omitempty"` - UpdatedTime *int64 `json:"updated_time,omitempty"` + CreationTime *wireInt64 `json:"creation_time,omitempty"` + UpdatedTime *wireInt64 `json:"updated_time,omitempty"` Deactivated *bool `json:"deactivated,omitempty"` - DeactivatedAt *int64 `json:"deactivated_at,omitempty"` + DeactivatedAt *wireInt64 `json:"deactivated_at,omitempty"` ErrorMessage *string `json:"error_message,omitempty"` ResourceId *string `json:"resource_id,omitempty"` GroupId *string `json:"group_id,omitempty"` @@ -2349,6 +2471,18 @@ func nccPrivateEndpointRuleFromWire(w *nccPrivateEndpointRuleWire) (*NccPrivateE if endpointMembers > 1 { return nil, fmt.Errorf("%s: multiple oneof members set", "NccPrivateEndpointRule.Endpoint") } + creationTimePublicValue, err := int64FromWire(w.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "NccPrivateEndpointRule.CreationTime", err) + } + updatedTimePublicValue, err := int64FromWire(w.UpdatedTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "NccPrivateEndpointRule.UpdatedTime", err) + } + deactivatedAtPublicValue, err := int64FromWire(w.DeactivatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "NccPrivateEndpointRule.DeactivatedAt", err) + } var endpointSelection isNccPrivateEndpointRule_Endpoint switch { case w.GcpEndpoint != nil: @@ -2363,10 +2497,10 @@ func nccPrivateEndpointRuleFromWire(w *nccPrivateEndpointRuleWire) (*NccPrivateE NetworkConnectivityConfigId: w.NetworkConnectivityConfigId, ConnectionState: w.ConnectionState, DomainNames: w.DomainNames, - CreationTime: w.CreationTime, - UpdatedTime: w.UpdatedTime, + CreationTime: creationTimePublicValue, + UpdatedTime: updatedTimePublicValue, Deactivated: w.Deactivated, - DeactivatedAt: w.DeactivatedAt, + DeactivatedAt: deactivatedAtPublicValue, ErrorMessage: w.ErrorMessage, ResourceId: w.ResourceId, GroupId: w.GroupId, @@ -2383,14 +2517,14 @@ func nccPrivateEndpointRuleFromWire(w *nccPrivateEndpointRuleWire) (*NccPrivateE type networkWire struct { NetworkId *string `json:"network_id,omitempty"` AccountId *string `json:"account_id,omitempty"` - WorkspaceId *int64 `json:"workspace_id,omitempty"` + WorkspaceId *wireInt64 `json:"workspace_id,omitempty"` VpcId *string `json:"vpc_id,omitempty"` SubnetIds []string `json:"subnet_ids,omitempty"` SecurityGroupIds []string `json:"security_group_ids,omitempty"` VpcStatus VpcStatus `json:"vpc_status,omitempty"` ErrorMessages []networkHealthWire `json:"error_messages,omitempty"` NetworkName *string `json:"network_name,omitempty"` - CreationTime *int64 `json:"creation_time,omitempty"` + CreationTime *wireInt64 `json:"creation_time,omitempty"` WarningMessages []networkWarningWire `json:"warning_messages,omitempty"` VpcEndpoints *networkVpcEndpointsWire `json:"vpc_endpoints,omitempty"` GcpNetworkInfo *gcpNetworkInfoWire `json:"gcp_network_info,omitempty"` @@ -2407,10 +2541,18 @@ func networkFromWire(w *networkWire) (*Network, error) { if networkInfoMembers > 1 { return nil, fmt.Errorf("%s: multiple oneof members set", "Network.NetworkInfo") } + workspaceIdPublicValue, err := int64FromWire(w.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Network.WorkspaceId", err) + } errorMessagesPublicValue, err := convertSlice(w.ErrorMessages, networkHealthFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "Network.ErrorMessages", err) } + creationTimePublicValue, err := int64FromWire(w.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Network.CreationTime", err) + } warningMessagesPublicValue, err := convertSlice(w.WarningMessages, networkWarningFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "Network.WarningMessages", err) @@ -2431,14 +2573,14 @@ func networkFromWire(w *networkWire) (*Network, error) { return &Network{ NetworkId: w.NetworkId, AccountId: w.AccountId, - WorkspaceId: w.WorkspaceId, + WorkspaceId: workspaceIdPublicValue, VpcId: w.VpcId, SubnetIds: w.SubnetIds, SecurityGroupIds: w.SecurityGroupIds, VpcStatus: w.VpcStatus, ErrorMessages: errorMessagesPublicValue, NetworkName: w.NetworkName, - CreationTime: w.CreationTime, + CreationTime: creationTimePublicValue, WarningMessages: warningMessagesPublicValue, VpcEndpoints: vpcEndpointsPublicValue, NetworkInfo: networkInfoSelection, @@ -2451,8 +2593,8 @@ type networkConnectivityConfigWire struct { Name *string `json:"name,omitempty"` Region *string `json:"region,omitempty"` EgressConfig *customerFacingNetworkConnectivityConfigEgressConfigWire `json:"egress_config,omitempty"` - UpdatedTime *int64 `json:"updated_time,omitempty"` - CreationTime *int64 `json:"creation_time,omitempty"` + UpdatedTime *wireInt64 `json:"updated_time,omitempty"` + CreationTime *wireInt64 `json:"creation_time,omitempty"` } func networkConnectivityConfigFromWire(w *networkConnectivityConfigWire) (*NetworkConnectivityConfig, error) { @@ -2463,14 +2605,22 @@ func networkConnectivityConfigFromWire(w *networkConnectivityConfigWire) (*Netwo if err != nil { return nil, fmt.Errorf("%s: %w", "NetworkConnectivityConfig.EgressConfig", err) } + updatedTimePublicValue, err := int64FromWire(w.UpdatedTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "NetworkConnectivityConfig.UpdatedTime", err) + } + creationTimePublicValue, err := int64FromWire(w.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "NetworkConnectivityConfig.CreationTime", err) + } return &NetworkConnectivityConfig{ NetworkConnectivityConfigId: w.NetworkConnectivityConfigId, AccountId: w.AccountId, Name: w.Name, Region: w.Region, EgressConfig: egressConfigPublicValue, - UpdatedTime: w.UpdatedTime, - CreationTime: w.CreationTime, + UpdatedTime: updatedTimePublicValue, + CreationTime: creationTimePublicValue, }, nil } @@ -2483,10 +2633,10 @@ type networkConnectivityConfigAwsPrivateEndpointRuleWire struct { ResourceNames []string `json:"resource_names,omitempty"` VpcEndpointId *string `json:"vpc_endpoint_id,omitempty"` ConnectionState NetworkConnectivityConfigAwsPrivateEndpointRule_PrivateLinkConnectionState `json:"connection_state,omitempty"` - CreationTime *int64 `json:"creation_time,omitempty"` - UpdatedTime *int64 `json:"updated_time,omitempty"` + CreationTime *wireInt64 `json:"creation_time,omitempty"` + UpdatedTime *wireInt64 `json:"updated_time,omitempty"` Deactivated *bool `json:"deactivated,omitempty"` - DeactivatedAt *int64 `json:"deactivated_at,omitempty"` + DeactivatedAt *wireInt64 `json:"deactivated_at,omitempty"` Enabled *bool `json:"enabled,omitempty"` ErrorMessage *string `json:"error_message,omitempty"` } @@ -2495,6 +2645,18 @@ func networkConnectivityConfigAwsPrivateEndpointRuleToWire(v *NetworkConnectivit if v == nil { return nil, nil } + creationTimeWireValue, err := int64ToWire(v.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "NetworkConnectivityConfigAwsPrivateEndpointRule.CreationTime", err) + } + updatedTimeWireValue, err := int64ToWire(v.UpdatedTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "NetworkConnectivityConfigAwsPrivateEndpointRule.UpdatedTime", err) + } + deactivatedAtWireValue, err := int64ToWire(v.DeactivatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "NetworkConnectivityConfigAwsPrivateEndpointRule.DeactivatedAt", err) + } return &networkConnectivityConfigAwsPrivateEndpointRuleWire{ RuleId: v.RuleId, NetworkConnectivityConfigId: v.NetworkConnectivityConfigId, @@ -2504,10 +2666,10 @@ func networkConnectivityConfigAwsPrivateEndpointRuleToWire(v *NetworkConnectivit ResourceNames: v.ResourceNames, VpcEndpointId: v.VpcEndpointId, ConnectionState: v.ConnectionState, - CreationTime: v.CreationTime, - UpdatedTime: v.UpdatedTime, + CreationTime: creationTimeWireValue, + UpdatedTime: updatedTimeWireValue, Deactivated: v.Deactivated, - DeactivatedAt: v.DeactivatedAt, + DeactivatedAt: deactivatedAtWireValue, Enabled: v.Enabled, ErrorMessage: v.ErrorMessage, }, nil @@ -2517,6 +2679,18 @@ func networkConnectivityConfigAwsPrivateEndpointRuleFromWire(w *networkConnectiv if w == nil { return nil, nil } + creationTimePublicValue, err := int64FromWire(w.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "NetworkConnectivityConfigAwsPrivateEndpointRule.CreationTime", err) + } + updatedTimePublicValue, err := int64FromWire(w.UpdatedTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "NetworkConnectivityConfigAwsPrivateEndpointRule.UpdatedTime", err) + } + deactivatedAtPublicValue, err := int64FromWire(w.DeactivatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "NetworkConnectivityConfigAwsPrivateEndpointRule.DeactivatedAt", err) + } return &NetworkConnectivityConfigAwsPrivateEndpointRule{ RuleId: w.RuleId, NetworkConnectivityConfigId: w.NetworkConnectivityConfigId, @@ -2526,10 +2700,10 @@ func networkConnectivityConfigAwsPrivateEndpointRuleFromWire(w *networkConnectiv ResourceNames: w.ResourceNames, VpcEndpointId: w.VpcEndpointId, ConnectionState: w.ConnectionState, - CreationTime: w.CreationTime, - UpdatedTime: w.UpdatedTime, + CreationTime: creationTimePublicValue, + UpdatedTime: updatedTimePublicValue, Deactivated: w.Deactivated, - DeactivatedAt: w.DeactivatedAt, + DeactivatedAt: deactivatedAtPublicValue, Enabled: w.Enabled, ErrorMessage: w.ErrorMessage, }, nil @@ -2542,10 +2716,10 @@ type networkConnectivityConfigAzurePrivateEndpointRuleWire struct { GroupId *string `json:"group_id,omitempty"` EndpointName *string `json:"endpoint_name,omitempty"` ConnectionState NetworkConnectivityConfigAzurePrivateEndpointRule_PrivateLinkConnectionState `json:"connection_state,omitempty"` - CreationTime *int64 `json:"creation_time,omitempty"` - UpdatedTime *int64 `json:"updated_time,omitempty"` + CreationTime *wireInt64 `json:"creation_time,omitempty"` + UpdatedTime *wireInt64 `json:"updated_time,omitempty"` Deactivated *bool `json:"deactivated,omitempty"` - DeactivatedAt *int64 `json:"deactivated_at,omitempty"` + DeactivatedAt *wireInt64 `json:"deactivated_at,omitempty"` DomainNames []string `json:"domain_names,omitempty"` ErrorMessage *string `json:"error_message,omitempty"` } @@ -2554,6 +2728,18 @@ func networkConnectivityConfigAzurePrivateEndpointRuleToWire(v *NetworkConnectiv if v == nil { return nil, nil } + creationTimeWireValue, err := int64ToWire(v.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "NetworkConnectivityConfigAzurePrivateEndpointRule.CreationTime", err) + } + updatedTimeWireValue, err := int64ToWire(v.UpdatedTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "NetworkConnectivityConfigAzurePrivateEndpointRule.UpdatedTime", err) + } + deactivatedAtWireValue, err := int64ToWire(v.DeactivatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "NetworkConnectivityConfigAzurePrivateEndpointRule.DeactivatedAt", err) + } return &networkConnectivityConfigAzurePrivateEndpointRuleWire{ RuleId: v.RuleId, NetworkConnectivityConfigId: v.NetworkConnectivityConfigId, @@ -2561,10 +2747,10 @@ func networkConnectivityConfigAzurePrivateEndpointRuleToWire(v *NetworkConnectiv GroupId: v.GroupId, EndpointName: v.EndpointName, ConnectionState: v.ConnectionState, - CreationTime: v.CreationTime, - UpdatedTime: v.UpdatedTime, + CreationTime: creationTimeWireValue, + UpdatedTime: updatedTimeWireValue, Deactivated: v.Deactivated, - DeactivatedAt: v.DeactivatedAt, + DeactivatedAt: deactivatedAtWireValue, DomainNames: v.DomainNames, ErrorMessage: v.ErrorMessage, }, nil @@ -2574,6 +2760,18 @@ func networkConnectivityConfigAzurePrivateEndpointRuleFromWire(w *networkConnect if w == nil { return nil, nil } + creationTimePublicValue, err := int64FromWire(w.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "NetworkConnectivityConfigAzurePrivateEndpointRule.CreationTime", err) + } + updatedTimePublicValue, err := int64FromWire(w.UpdatedTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "NetworkConnectivityConfigAzurePrivateEndpointRule.UpdatedTime", err) + } + deactivatedAtPublicValue, err := int64FromWire(w.DeactivatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "NetworkConnectivityConfigAzurePrivateEndpointRule.DeactivatedAt", err) + } return &NetworkConnectivityConfigAzurePrivateEndpointRule{ RuleId: w.RuleId, NetworkConnectivityConfigId: w.NetworkConnectivityConfigId, @@ -2581,10 +2779,10 @@ func networkConnectivityConfigAzurePrivateEndpointRuleFromWire(w *networkConnect GroupId: w.GroupId, EndpointName: w.EndpointName, ConnectionState: w.ConnectionState, - CreationTime: w.CreationTime, - UpdatedTime: w.UpdatedTime, + CreationTime: creationTimePublicValue, + UpdatedTime: updatedTimePublicValue, Deactivated: w.Deactivated, - DeactivatedAt: w.DeactivatedAt, + DeactivatedAt: deactivatedAtPublicValue, DomainNames: w.DomainNames, ErrorMessage: w.ErrorMessage, }, nil @@ -3000,10 +3198,10 @@ type updatePrivateEndpointRuleWire struct { NetworkConnectivityConfigId *string `json:"network_connectivity_config_id,omitempty"` ConnectionState NccPrivateEndpointRule_PrivateLinkConnectionState `json:"connection_state,omitempty"` DomainNames []string `json:"domain_names,omitempty"` - CreationTime *int64 `json:"creation_time,omitempty"` - UpdatedTime *int64 `json:"updated_time,omitempty"` + CreationTime *wireInt64 `json:"creation_time,omitempty"` + UpdatedTime *wireInt64 `json:"updated_time,omitempty"` Deactivated *bool `json:"deactivated,omitempty"` - DeactivatedAt *int64 `json:"deactivated_at,omitempty"` + DeactivatedAt *wireInt64 `json:"deactivated_at,omitempty"` ErrorMessage *string `json:"error_message,omitempty"` ResourceId *string `json:"resource_id,omitempty"` GroupId *string `json:"group_id,omitempty"` @@ -3020,6 +3218,18 @@ func updatePrivateEndpointRuleToWire(v *UpdatePrivateEndpointRule) (*updatePriva if v == nil { return nil, nil } + creationTimeWireValue, err := int64ToWire(v.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdatePrivateEndpointRule.CreationTime", err) + } + updatedTimeWireValue, err := int64ToWire(v.UpdatedTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdatePrivateEndpointRule.UpdatedTime", err) + } + deactivatedAtWireValue, err := int64ToWire(v.DeactivatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdatePrivateEndpointRule.DeactivatedAt", err) + } var endpointGcpEndpointWire *gcpEndpointWire switch value := v.Endpoint.(type) { case nil: @@ -3039,10 +3249,10 @@ func updatePrivateEndpointRuleToWire(v *UpdatePrivateEndpointRule) (*updatePriva NetworkConnectivityConfigId: v.NetworkConnectivityConfigId, ConnectionState: v.ConnectionState, DomainNames: v.DomainNames, - CreationTime: v.CreationTime, - UpdatedTime: v.UpdatedTime, + CreationTime: creationTimeWireValue, + UpdatedTime: updatedTimeWireValue, Deactivated: v.Deactivated, - DeactivatedAt: v.DeactivatedAt, + DeactivatedAt: deactivatedAtWireValue, ErrorMessage: v.ErrorMessage, ResourceId: v.ResourceId, GroupId: v.GroupId, @@ -3058,7 +3268,7 @@ func updatePrivateEndpointRuleToWire(v *UpdatePrivateEndpointRule) (*updatePriva type updateWorkspaceNetworkOptionRequestWire struct { AccountId *string `json:"account_id,omitempty"` - WorkspaceId *int64 `json:"workspace_id,omitempty"` + WorkspaceId *wireInt64 `json:"workspace_id,omitempty"` WorkspaceNetworkOption *workspaceNetworkOptionWire `json:"workspace_network_option,omitempty"` } @@ -3066,13 +3276,17 @@ func updateWorkspaceNetworkOptionRequestToWire(v *UpdateWorkspaceNetworkOptionRe if v == nil { return nil, nil } + workspaceIdWireValue, err := int64ToWire(v.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateWorkspaceNetworkOptionRequest.WorkspaceId", err) + } workspaceNetworkOptionWireValue, err := workspaceNetworkOptionToWire(v.WorkspaceNetworkOption) if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateWorkspaceNetworkOptionRequest.WorkspaceNetworkOption", err) } return &updateWorkspaceNetworkOptionRequestWire{ AccountId: v.AccountId, - WorkspaceId: v.WorkspaceId, + WorkspaceId: workspaceIdWireValue, WorkspaceNetworkOption: workspaceNetworkOptionWireValue, }, nil } @@ -3125,17 +3339,21 @@ func vpcEndpointFromWire(w *vpcEndpointWire) (*VpcEndpoint, error) { } type workspaceNetworkOptionWire struct { - NetworkPolicyId *string `json:"network_policy_id,omitempty"` - WorkspaceId *int64 `json:"workspace_id,omitempty"` + NetworkPolicyId *string `json:"network_policy_id,omitempty"` + WorkspaceId *wireInt64 `json:"workspace_id,omitempty"` } func workspaceNetworkOptionToWire(v *WorkspaceNetworkOption) (*workspaceNetworkOptionWire, error) { if v == nil { return nil, nil } + workspaceIdWireValue, err := int64ToWire(v.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "WorkspaceNetworkOption.WorkspaceId", err) + } return &workspaceNetworkOptionWire{ NetworkPolicyId: v.NetworkPolicyId, - WorkspaceId: v.WorkspaceId, + WorkspaceId: workspaceIdWireValue, }, nil } @@ -3143,9 +3361,13 @@ func workspaceNetworkOptionFromWire(w *workspaceNetworkOptionWire) (*WorkspaceNe if w == nil { return nil, nil } + workspaceIdPublicValue, err := int64FromWire(w.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "WorkspaceNetworkOption.WorkspaceId", err) + } return &WorkspaceNetworkOption{ NetworkPolicyId: w.NetworkPolicyId, - WorkspaceId: w.WorkspaceId, + WorkspaceId: workspaceIdPublicValue, }, nil } diff --git a/notificationdestinations/CHANGELOG.md b/notificationdestinations/CHANGELOG.md index 6224c04..19f237c 100644 --- a/notificationdestinations/CHANGELOG.md +++ b/notificationdestinations/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/notificationdestinations/go.mod b/notificationdestinations/go.mod index 9c9dc20..1195ad9 100644 --- a/notificationdestinations/go.mod +++ b/notificationdestinations/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/notificationdestinations/internal/version.go b/notificationdestinations/internal/version.go index 55891b0..40538aa 100644 --- a/notificationdestinations/internal/version.go +++ b/notificationdestinations/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-notificationdestinations" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/notificationdestinations/v1/client.go b/notificationdestinations/v1/client.go old mode 100755 new mode 100644 index b41d67e..81df4ea --- a/notificationdestinations/v1/client.go +++ b/notificationdestinations/v1/client.go @@ -75,8 +75,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Creates a notification destination. Requires workspace admin permissions. -func (c *internalClient) CreateNotificationDestination(ctx context.Context, req *CreateNotificationDestinationRequest, opts ...call.Option) (*NotificationDestination, error) { - wireReq, err := createNotificationDestinationRequestToWire(req) +func (c *internalClient) CreateNotificationDestination(ctx context.Context, req CreateNotificationDestinationRequest, opts ...call.Option) (*NotificationDestination, error) { + wireReq, err := createNotificationDestinationRequestToWire(&req) if err != nil { return nil, err } @@ -141,7 +141,7 @@ func (c *internalClient) CreateNotificationDestination(ctx context.Context, req } // Deletes a notification destination. Requires workspace admin permissions. -func (c *internalClient) DeleteNotificationDestination(ctx context.Context, req *DeleteNotificationDestinationRequest, opts ...call.Option) (*Empty, error) { +func (c *internalClient) DeleteNotificationDestination(ctx context.Context, req DeleteNotificationDestinationRequest, opts ...call.Option) (*Empty, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -155,7 +155,11 @@ func (c *internalClient) DeleteNotificationDestination(ctx context.Context, req } pb := pathBuilder{} pb.literal("/api/2.0/notification-destinations/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -195,7 +199,7 @@ func (c *internalClient) DeleteNotificationDestination(ctx context.Context, req } // Gets a notification destination. -func (c *internalClient) GetNotificationDestination(ctx context.Context, req *GetNotificationDestinationRequest, opts ...call.Option) (*NotificationDestination, error) { +func (c *internalClient) GetNotificationDestination(ctx context.Context, req GetNotificationDestinationRequest, opts ...call.Option) (*NotificationDestination, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -209,7 +213,11 @@ func (c *internalClient) GetNotificationDestination(ctx context.Context, req *Ge } pb := pathBuilder{} pb.literal("/api/2.0/notification-destinations/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -255,8 +263,8 @@ func (c *internalClient) GetNotificationDestination(ctx context.Context, req *Ge } // Lists notification destinations. -func (c *internalClient) ListNotificationDestinations(ctx context.Context, req *ListNotificationDestinationsRequest, opts ...call.Option) (*ListNotificationDestinationsResponse, error) { - wireReq, err := listNotificationDestinationsRequestToWire(req) +func (c *internalClient) ListNotificationDestinations(ctx context.Context, req ListNotificationDestinationsRequest, opts ...call.Option) (*ListNotificationDestinationsResponse, error) { + wireReq, err := listNotificationDestinationsRequestToWire(&req) if err != nil { return nil, err } @@ -326,7 +334,7 @@ func (c *internalClient) ListNotificationDestinations(ctx context.Context, req * // // For example: // -// for item, err := range c.ListNotificationDestinationsIter(ctx, &ListNotificationDestinationsRequest{}) { +// for item, err := range c.ListNotificationDestinationsIter(ctx, ListNotificationDestinationsRequest{}) { // if err != nil { // return err // } @@ -338,16 +346,13 @@ func (c *internalClient) ListNotificationDestinations(ctx context.Context, req * // // Callers who need custom pagination logic should use // ListNotificationDestinations directly. -func (c *internalClient) ListNotificationDestinationsIter(ctx context.Context, req *ListNotificationDestinationsRequest, opts ...call.Option) iter.Seq2[*ListNotificationDestinationsResult, error] { +func (c *internalClient) ListNotificationDestinationsIter(ctx context.Context, req ListNotificationDestinationsRequest, opts ...call.Option) iter.Seq2[*ListNotificationDestinationsResult, error] { return func(yield func(*ListNotificationDestinationsResult, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListNotificationDestinationsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListNotificationDestinations(ctx, &pageReq, opts...) + resp, err := c.ListNotificationDestinations(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -367,8 +372,8 @@ func (c *internalClient) ListNotificationDestinationsIter(ctx context.Context, r // Updates a notification destination. Requires workspace admin permissions. At // least one field is required in the request body. -func (c *internalClient) UpdateNotificationDestination(ctx context.Context, req *UpdateNotificationDestinationRequest, opts ...call.Option) (*NotificationDestination, error) { - wireReq, err := updateNotificationDestinationRequestToWire(req) +func (c *internalClient) UpdateNotificationDestination(ctx context.Context, req UpdateNotificationDestinationRequest, opts ...call.Option) (*NotificationDestination, error) { + wireReq, err := updateNotificationDestinationRequestToWire(&req) if err != nil { return nil, err } @@ -389,7 +394,11 @@ func (c *internalClient) UpdateNotificationDestination(ctx context.Context, req } pb := pathBuilder{} pb.literal("/api/2.0/notification-destinations/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/notificationdestinations/v1/genhelper.go b/notificationdestinations/v1/genhelper.go old mode 100755 new mode 100644 index 691df90..2b18643 --- a/notificationdestinations/v1/genhelper.go +++ b/notificationdestinations/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/notificationdestinations/v1/wire.go b/notificationdestinations/v1/wire.go old mode 100755 new mode 100644 index 700ac68..ce64d06 --- a/notificationdestinations/v1/wire.go +++ b/notificationdestinations/v1/wire.go @@ -3,9 +3,55 @@ package notificationdestinations import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type configWire struct { Slack *slackConfigWire `json:"slack,omitempty"` Email *emailConfigWire `json:"email,omitempty"` @@ -217,17 +263,21 @@ func genericWebhookConfigFromWire(w *genericWebhookConfigWire) (*GenericWebhookC } type listNotificationDestinationsRequestWire struct { - PageToken *string `json:"page_token,omitempty"` - PageSize *int64 `json:"page_size,omitempty"` + PageToken *string `json:"page_token,omitempty"` + PageSize *wireInt64 `json:"page_size,omitempty"` } func listNotificationDestinationsRequestToWire(v *ListNotificationDestinationsRequest) (*listNotificationDestinationsRequestWire, error) { if v == nil { return nil, nil } + pageSizeWireValue, err := int64ToWire(v.PageSize) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListNotificationDestinationsRequest.PageSize", err) + } return &listNotificationDestinationsRequestWire{ PageToken: v.PageToken, - PageSize: v.PageSize, + PageSize: pageSizeWireValue, }, nil } diff --git a/oauth/CHANGELOG.md b/oauth/CHANGELOG.md index 6224c04..19f237c 100644 --- a/oauth/CHANGELOG.md +++ b/oauth/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/oauth/go.mod b/oauth/go.mod index 3cf3d0e..7fdb5c7 100644 --- a/oauth/go.mod +++ b/oauth/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/oauth/internal/version.go b/oauth/internal/version.go index ffc3a37..815f9bf 100644 --- a/oauth/internal/version.go +++ b/oauth/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-oauth" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/oauth/v1/client.go b/oauth/v1/client.go old mode 100755 new mode 100644 index e55ce80..9ca0eb0 --- a/oauth/v1/client.go +++ b/oauth/v1/client.go @@ -81,8 +81,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // // [CustomAppIntegration/get]: https://docs.databricks.com/api/account/customappintegration/get // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateCustomOAuthAppIntegration(ctx context.Context, req *CreateCustomOAuthAppIntegrationRequest, opts ...call.Option) (*CustomOAuthAppIntegrationSecret, error) { - wireReq, err := createCustomOAuthAppIntegrationRequestToWire(req) +func (c *internalClient) CreateCustomOAuthAppIntegration(ctx context.Context, req CreateCustomOAuthAppIntegrationRequest, opts ...call.Option) (*CustomOAuthAppIntegrationSecret, error) { + wireReq, err := createCustomOAuthAppIntegrationRequestToWire(&req) if err != nil { return nil, err } @@ -158,8 +158,8 @@ func (c *internalClient) CreateCustomOAuthAppIntegration(ctx context.Context, re // // [PublishedAppIntegration/get]: https://docs.databricks.com/api/account/publishedappintegration/get // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreatePublishedOAuthAppIntegration(ctx context.Context, req *CreatePublishedOAuthAppIntegrationRequest, opts ...call.Option) (*CreatePublishedOAuthAppIntegrationResponse, error) { - wireReq, err := createPublishedOAuthAppIntegrationRequestToWire(req) +func (c *internalClient) CreatePublishedOAuthAppIntegration(ctx context.Context, req CreatePublishedOAuthAppIntegrationRequest, opts ...call.Option) (*CreatePublishedOAuthAppIntegrationResponse, error) { + wireReq, err := createPublishedOAuthAppIntegrationRequestToWire(&req) if err != nil { return nil, err } @@ -233,7 +233,7 @@ func (c *internalClient) CreatePublishedOAuthAppIntegration(ctx context.Context, // // [CustomAppIntegration/get]: https://docs.databricks.com/api/account/customappintegration/get // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteCustomOAuthAppIntegration(ctx context.Context, req *DeleteCustomOAuthAppIntegrationRequest, opts ...call.Option) (*DeleteCustomOAuthAppIntegrationResponse, error) { +func (c *internalClient) DeleteCustomOAuthAppIntegration(ctx context.Context, req DeleteCustomOAuthAppIntegrationRequest, opts ...call.Option) (*DeleteCustomOAuthAppIntegrationResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -250,7 +250,11 @@ func (c *internalClient) DeleteCustomOAuthAppIntegration(ctx context.Context, re pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/oauth2/custom-app-integrations/") - pb.singleSegment(*req.IntegrationId) + if req.IntegrationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.IntegrationId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -294,7 +298,7 @@ func (c *internalClient) DeleteCustomOAuthAppIntegration(ctx context.Context, re // // [PublishedAppIntegration/get]: https://docs.databricks.com/api/account/publishedappintegration/get // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeletePublishedOAuthAppIntegration(ctx context.Context, req *DeletePublishedOAuthAppIntegrationRequest, opts ...call.Option) (*DeletePublishedOAuthAppIntegrationResponse, error) { +func (c *internalClient) DeletePublishedOAuthAppIntegration(ctx context.Context, req DeletePublishedOAuthAppIntegrationRequest, opts ...call.Option) (*DeletePublishedOAuthAppIntegrationResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -311,7 +315,11 @@ func (c *internalClient) DeletePublishedOAuthAppIntegration(ctx context.Context, pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/oauth2/published-app-integrations/") - pb.singleSegment(*req.IntegrationId) + if req.IntegrationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.IntegrationId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -352,7 +360,7 @@ func (c *internalClient) DeletePublishedOAuthAppIntegration(ctx context.Context, // Gets the Custom OAuth App Integration for the given integration id. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetCustomOAuthAppIntegration(ctx context.Context, req *GetCustomOAuthAppIntegrationRequest, opts ...call.Option) (*CustomOAuthAppIntegration, error) { +func (c *internalClient) GetCustomOAuthAppIntegration(ctx context.Context, req GetCustomOAuthAppIntegrationRequest, opts ...call.Option) (*CustomOAuthAppIntegration, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -369,7 +377,11 @@ func (c *internalClient) GetCustomOAuthAppIntegration(ctx context.Context, req * pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/oauth2/custom-app-integrations/") - pb.singleSegment(*req.IntegrationId) + if req.IntegrationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.IntegrationId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -416,7 +428,7 @@ func (c *internalClient) GetCustomOAuthAppIntegration(ctx context.Context, req * // Gets the Published OAuth App Integration for the given integration id. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetPublishedOAuthAppIntegration(ctx context.Context, req *GetPublishedOAuthAppIntegrationRequest, opts ...call.Option) (*PublishedOAuthAppIntegration, error) { +func (c *internalClient) GetPublishedOAuthAppIntegration(ctx context.Context, req GetPublishedOAuthAppIntegrationRequest, opts ...call.Option) (*PublishedOAuthAppIntegration, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -433,7 +445,11 @@ func (c *internalClient) GetPublishedOAuthAppIntegration(ctx context.Context, re pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/oauth2/published-app-integrations/") - pb.singleSegment(*req.IntegrationId) + if req.IntegrationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.IntegrationId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -480,8 +496,8 @@ func (c *internalClient) GetPublishedOAuthAppIntegration(ctx context.Context, re // Get the list of custom OAuth app integrations for the specified // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListCustomOAuthAppIntegrations(ctx context.Context, req *ListCustomOAuthAppIntegrationsRequest, opts ...call.Option) (*ListCustomOAuthAppIntegrationsResponse, error) { - wireReq, err := listCustomOAuthAppIntegrationsRequestToWire(req) +func (c *internalClient) ListCustomOAuthAppIntegrations(ctx context.Context, req ListCustomOAuthAppIntegrationsRequest, opts ...call.Option) (*ListCustomOAuthAppIntegrationsResponse, error) { + wireReq, err := listCustomOAuthAppIntegrationsRequestToWire(&req) if err != nil { return nil, err } @@ -559,7 +575,7 @@ func (c *internalClient) ListCustomOAuthAppIntegrations(ctx context.Context, req // // For example: // -// for item, err := range c.ListCustomOAuthAppIntegrationsIter(ctx, &ListCustomOAuthAppIntegrationsRequest{}) { +// for item, err := range c.ListCustomOAuthAppIntegrationsIter(ctx, ListCustomOAuthAppIntegrationsRequest{}) { // if err != nil { // return err // } @@ -571,16 +587,13 @@ func (c *internalClient) ListCustomOAuthAppIntegrations(ctx context.Context, req // // Callers who need custom pagination logic should use // ListCustomOAuthAppIntegrations directly. -func (c *internalClient) ListCustomOAuthAppIntegrationsIter(ctx context.Context, req *ListCustomOAuthAppIntegrationsRequest, opts ...call.Option) iter.Seq2[*CustomOAuthAppIntegration, error] { +func (c *internalClient) ListCustomOAuthAppIntegrationsIter(ctx context.Context, req ListCustomOAuthAppIntegrationsRequest, opts ...call.Option) iter.Seq2[*CustomOAuthAppIntegration, error] { return func(yield func(*CustomOAuthAppIntegration, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListCustomOAuthAppIntegrationsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListCustomOAuthAppIntegrations(ctx, &pageReq, opts...) + resp, err := c.ListCustomOAuthAppIntegrations(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -600,8 +613,8 @@ func (c *internalClient) ListCustomOAuthAppIntegrationsIter(ctx context.Context, // Get the list of published OAuth app integrations for the specified // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListPublishedOAuthAppIntegrations(ctx context.Context, req *ListPublishedOAuthAppIntegrationsRequest, opts ...call.Option) (*ListPublishedOAuthAppIntegrationsResponse, error) { - wireReq, err := listPublishedOAuthAppIntegrationsRequestToWire(req) +func (c *internalClient) ListPublishedOAuthAppIntegrations(ctx context.Context, req ListPublishedOAuthAppIntegrationsRequest, opts ...call.Option) (*ListPublishedOAuthAppIntegrationsResponse, error) { + wireReq, err := listPublishedOAuthAppIntegrationsRequestToWire(&req) if err != nil { return nil, err } @@ -676,7 +689,7 @@ func (c *internalClient) ListPublishedOAuthAppIntegrations(ctx context.Context, // // For example: // -// for item, err := range c.ListPublishedOAuthAppIntegrationsIter(ctx, &ListPublishedOAuthAppIntegrationsRequest{}) { +// for item, err := range c.ListPublishedOAuthAppIntegrationsIter(ctx, ListPublishedOAuthAppIntegrationsRequest{}) { // if err != nil { // return err // } @@ -688,16 +701,13 @@ func (c *internalClient) ListPublishedOAuthAppIntegrations(ctx context.Context, // // Callers who need custom pagination logic should use // ListPublishedOAuthAppIntegrations directly. -func (c *internalClient) ListPublishedOAuthAppIntegrationsIter(ctx context.Context, req *ListPublishedOAuthAppIntegrationsRequest, opts ...call.Option) iter.Seq2[*PublishedOAuthAppIntegration, error] { +func (c *internalClient) ListPublishedOAuthAppIntegrationsIter(ctx context.Context, req ListPublishedOAuthAppIntegrationsRequest, opts ...call.Option) iter.Seq2[*PublishedOAuthAppIntegration, error] { return func(yield func(*PublishedOAuthAppIntegration, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListPublishedOAuthAppIntegrationsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListPublishedOAuthAppIntegrations(ctx, &pageReq, opts...) + resp, err := c.ListPublishedOAuthAppIntegrations(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -717,8 +727,8 @@ func (c *internalClient) ListPublishedOAuthAppIntegrationsIter(ctx context.Conte // Get all the available published OAuth apps in . // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListPublishedOAuthApps(ctx context.Context, req *ListPublishedOAuthAppsRequest, opts ...call.Option) (*ListPublishedOAuthAppsResponse, error) { - wireReq, err := listPublishedOAuthAppsRequestToWire(req) +func (c *internalClient) ListPublishedOAuthApps(ctx context.Context, req ListPublishedOAuthAppsRequest, opts ...call.Option) (*ListPublishedOAuthAppsResponse, error) { + wireReq, err := listPublishedOAuthAppsRequestToWire(&req) if err != nil { return nil, err } @@ -793,7 +803,7 @@ func (c *internalClient) ListPublishedOAuthApps(ctx context.Context, req *ListPu // // For example: // -// for item, err := range c.ListPublishedOAuthAppsIter(ctx, &ListPublishedOAuthAppsRequest{}) { +// for item, err := range c.ListPublishedOAuthAppsIter(ctx, ListPublishedOAuthAppsRequest{}) { // if err != nil { // return err // } @@ -805,16 +815,13 @@ func (c *internalClient) ListPublishedOAuthApps(ctx context.Context, req *ListPu // // Callers who need custom pagination logic should use // ListPublishedOAuthApps directly. -func (c *internalClient) ListPublishedOAuthAppsIter(ctx context.Context, req *ListPublishedOAuthAppsRequest, opts ...call.Option) iter.Seq2[*PublishedOAuthApp, error] { +func (c *internalClient) ListPublishedOAuthAppsIter(ctx context.Context, req ListPublishedOAuthAppsRequest, opts ...call.Option) iter.Seq2[*PublishedOAuthApp, error] { return func(yield func(*PublishedOAuthApp, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListPublishedOAuthAppsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListPublishedOAuthApps(ctx, &pageReq, opts...) + resp, err := c.ListPublishedOAuthApps(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -837,8 +844,8 @@ func (c *internalClient) ListPublishedOAuthAppsIter(ctx context.Context, req *Li // // [CustomAppIntegration/get]: https://docs.databricks.com/api/account/customappintegration/get // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdateCustomOAuthAppIntegration(ctx context.Context, req *UpdateCustomOAuthAppIntegrationRequest, opts ...call.Option) (*UpdateCustomOAuthAppIntegrationResponse, error) { - wireReq, err := updateCustomOAuthAppIntegrationRequestToWire(req) +func (c *internalClient) UpdateCustomOAuthAppIntegration(ctx context.Context, req UpdateCustomOAuthAppIntegrationRequest, opts ...call.Option) (*UpdateCustomOAuthAppIntegrationResponse, error) { + wireReq, err := updateCustomOAuthAppIntegrationRequestToWire(&req) if err != nil { return nil, err } @@ -862,7 +869,11 @@ func (c *internalClient) UpdateCustomOAuthAppIntegration(ctx context.Context, re pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/oauth2/custom-app-integrations/") - pb.singleSegment(*req.IntegrationId) + if req.IntegrationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.IntegrationId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -907,8 +918,8 @@ func (c *internalClient) UpdateCustomOAuthAppIntegration(ctx context.Context, re // // [PublishedAppIntegration/get]: https://docs.databricks.com/api/account/publishedappintegration/get // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdatePublishedOAuthAppIntegration(ctx context.Context, req *UpdatePublishedOAuthAppIntegrationRequest, opts ...call.Option) (*UpdatePublishedOAuthAppIntegrationResponse, error) { - wireReq, err := updatePublishedOAuthAppIntegrationRequestToWire(req) +func (c *internalClient) UpdatePublishedOAuthAppIntegration(ctx context.Context, req UpdatePublishedOAuthAppIntegrationRequest, opts ...call.Option) (*UpdatePublishedOAuthAppIntegrationResponse, error) { + wireReq, err := updatePublishedOAuthAppIntegrationRequestToWire(&req) if err != nil { return nil, err } @@ -932,7 +943,11 @@ func (c *internalClient) UpdatePublishedOAuthAppIntegration(ctx context.Context, pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/oauth2/published-app-integrations/") - pb.singleSegment(*req.IntegrationId) + if req.IntegrationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.IntegrationId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/oauth/v1/genhelper.go b/oauth/v1/genhelper.go old mode 100755 new mode 100644 index 1f22dff..f39347b --- a/oauth/v1/genhelper.go +++ b/oauth/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/oauth/v1/wire.go b/oauth/v1/wire.go old mode 100755 new mode 100644 index b3852a2..213931f --- a/oauth/v1/wire.go +++ b/oauth/v1/wire.go @@ -3,9 +3,55 @@ package oauth import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type createCustomOAuthAppIntegrationRequestWire struct { AccountId *string `json:"account_id,omitempty"` RedirectUrls []string `json:"redirect_urls,omitempty"` @@ -77,7 +123,7 @@ type customOAuthAppIntegrationWire struct { Confidential *bool `json:"confidential,omitempty"` TokenAccessPolicy *tokenAccessPolicyWire `json:"token_access_policy,omitempty"` Scopes []string `json:"scopes,omitempty"` - CreatedBy *int64 `json:"created_by,omitempty"` + CreatedBy *wireInt64 `json:"created_by,omitempty"` CreateTime *string `json:"create_time,omitempty"` CreatorUsername *string `json:"creator_username,omitempty"` UserAuthorizedScopes []string `json:"user_authorized_scopes,omitempty"` @@ -91,6 +137,10 @@ func customOAuthAppIntegrationFromWire(w *customOAuthAppIntegrationWire) (*Custo if err != nil { return nil, fmt.Errorf("%s: %w", "CustomOAuthAppIntegration.TokenAccessPolicy", err) } + createdByPublicValue, err := int64FromWire(w.CreatedBy) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CustomOAuthAppIntegration.CreatedBy", err) + } return &CustomOAuthAppIntegration{ IntegrationId: w.IntegrationId, ClientId: w.ClientId, @@ -99,7 +149,7 @@ func customOAuthAppIntegrationFromWire(w *customOAuthAppIntegrationWire) (*Custo Confidential: w.Confidential, TokenAccessPolicy: tokenAccessPolicyPublicValue, Scopes: w.Scopes, - CreatedBy: w.CreatedBy, + CreatedBy: createdByPublicValue, CreateTime: w.CreateTime, CreatorUsername: w.CreatorUsername, UserAuthorizedScopes: w.UserAuthorizedScopes, @@ -263,7 +313,7 @@ type publishedOAuthAppIntegrationWire struct { IntegrationId *string `json:"integration_id,omitempty"` Name *string `json:"name,omitempty"` TokenAccessPolicy *tokenAccessPolicyWire `json:"token_access_policy,omitempty"` - CreatedBy *int64 `json:"created_by,omitempty"` + CreatedBy *wireInt64 `json:"created_by,omitempty"` CreateTime *string `json:"create_time,omitempty"` } @@ -275,12 +325,16 @@ func publishedOAuthAppIntegrationFromWire(w *publishedOAuthAppIntegrationWire) ( if err != nil { return nil, fmt.Errorf("%s: %w", "PublishedOAuthAppIntegration.TokenAccessPolicy", err) } + createdByPublicValue, err := int64FromWire(w.CreatedBy) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PublishedOAuthAppIntegration.CreatedBy", err) + } return &PublishedOAuthAppIntegration{ AppId: w.AppId, IntegrationId: w.IntegrationId, Name: w.Name, TokenAccessPolicy: tokenAccessPolicyPublicValue, - CreatedBy: w.CreatedBy, + CreatedBy: createdByPublicValue, CreateTime: w.CreateTime, }, nil } diff --git a/options/CHANGELOG.md b/options/CHANGELOG.md index 6224c04..19f237c 100644 --- a/options/CHANGELOG.md +++ b/options/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/options/client/client.go b/options/client/client.go index 940f985..35a3232 100644 --- a/options/client/client.go +++ b/options/client/client.go @@ -88,29 +88,39 @@ func WithWorkspaceID(id string) Option { } } -// WithoutProfileResolution returns an Option that entirely disables profile -// resolution. This is useful when you want your client to only be explicitly -// configured in code. -func WithoutProfileResolution() Option { +// WithoutConfigFile returns an Option that disables loading client +// configuration from a config file. It cannot be combined with +// [WithConfigFile] or [WithProfile]. +func WithoutConfigFile() Option { return func(c *internaloptions.ClientOptions) error { - c.DisableProfileResolution = true + c.DisableConfigFile = true return nil } } -// WithProfileFile returns an Option that sets the profile file to use for -// profile resolution. By default, the profile file is resolved from the +// WithoutEnv returns an Option that disables overlaying client configuration +// from environment variables. It does not affect DATABRICKS_CONFIG_FILE or +// DATABRICKS_CONFIG_PROFILE, which select the profile file and name. +func WithoutEnv() Option { + return func(c *internaloptions.ClientOptions) error { + c.DisableEnv = true + return nil + } +} + +// WithConfigFile returns an Option that sets the config file to use for +// profile resolution. By default, the config file is resolved from the // environment variable $DATABRICKS_CONFIG_FILE. -func WithProfileFile(file string) Option { +func WithConfigFile(file string) Option { return func(c *internaloptions.ClientOptions) error { - c.ProfileFile = file + c.ConfigFile = file return nil } } // WithProfile returns an Option that sets the profile name to use for // profile resolution. By default, the profile name is resolved from the -// environment variable $DATABRICKS_CONFIG_NAME. +// environment variable $DATABRICKS_CONFIG_PROFILE. func WithProfile(name string) Option { return func(c *internaloptions.ClientOptions) error { c.ProfileName = name diff --git a/options/client/client_test.go b/options/client/client_test.go index 901663f..1a17192 100644 --- a/options/client/client_test.go +++ b/options/client/client_test.go @@ -22,6 +22,9 @@ func TestOptionsApply_AllFields(t *testing.T) { WithCredentials(creds), WithTimeout(7 * time.Second), WithLogger(logger), + WithConfigFile("databrickscfg"), + WithProfile("workspace"), + WithoutEnv(), } cfg := internaloptions.ClientOptions{} @@ -46,6 +49,23 @@ func TestOptionsApply_AllFields(t *testing.T) { if cfg.Logger != logger { t.Error("Logger mismatch") } + if cfg.ConfigFile != "databrickscfg" { + t.Errorf("ConfigFile = %q", cfg.ConfigFile) + } + if cfg.ProfileName != "workspace" { + t.Errorf("ProfileName = %q", cfg.ProfileName) + } + if !cfg.DisableEnv { + t.Error("DisableEnv = false, want true") + } + + withoutConfigFileCfg := internaloptions.ClientOptions{} + if err := WithoutConfigFile()(&withoutConfigFileCfg); err != nil { + t.Fatalf("WithoutConfigFile: %v", err) + } + if !withoutConfigFileCfg.DisableConfigFile { + t.Error("DisableConfigFile = false, want true") + } } type stubCredentials struct{} diff --git a/options/go.mod b/options/go.mod index b05da62..c59a22a 100644 --- a/options/go.mod +++ b/options/go.mod @@ -8,14 +8,19 @@ replace ( ) require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 ) require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/options/go.sum b/options/go.sum index 2b9bf4b..3f1d82f 100644 --- a/options/go.sum +++ b/options/go.sum @@ -1,14 +1,32 @@ +github.com/databricks/databricks-sdk-go v0.92.0 h1:Pvm/LvEXetOYJPgQFeewhmtkKC4z79AK3PHC5tlC+VQ= +github.com/databricks/databricks-sdk-go v0.92.0/go.mod h1:hWoHnHbNLjPKiTm5K/7bcIv3J3Pkgo5x9pPzh8K3RVE= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/options/internal/version.go b/options/internal/version.go index 8f6636e..c8e1b58 100644 --- a/options/internal/version.go +++ b/options/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-options" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/options/internaloptions/internaloptions.go b/options/internaloptions/internaloptions.go index bd483da..aea6ef6 100644 --- a/options/internaloptions/internaloptions.go +++ b/options/internaloptions/internaloptions.go @@ -23,9 +23,10 @@ import ( // client.Option values. type ClientOptions struct { // Profile resolution. - ProfileName string - ProfileFile string - DisableProfileResolution bool + ProfileName string + ConfigFile string + DisableConfigFile bool + DisableEnv bool Host string AccountID string @@ -43,6 +44,10 @@ type ClientOptions struct { // Resolve always populates the HTTPClient and Logger fields with default // values if not provided. func (c *ClientOptions) Resolve() error { + if c.DisableConfigFile && (c.ConfigFile != "" || c.ProfileName != "") { + return errors.New("cannot disable config file resolution when a config file or profile is specified") + } + if c.Logger == nil { c.Logger = slog.New(slog.DiscardHandler) } @@ -64,18 +69,22 @@ func (c *ClientOptions) Resolve() error { // resolve fills unset options from the profile. Explicitly set options take // precedence and are never overwritten. func (c *ClientOptions) resolve() error { - if c.DisableProfileResolution { - return nil + var opts []profiles.ResolveOption + if !c.DisableConfigFile { + if c.ProfileName != "" { + opts = append(opts, profiles.WithProfile(c.ProfileName)) + } else { + opts = append(opts, profiles.WithDefaultProfile()) + } + if c.ConfigFile != "" { + opts = append(opts, profiles.WithFile(c.ConfigFile)) + } } - - opts := []profiles.ResolveOption{profiles.WithEnv()} - if c.ProfileName != "" { - opts = append(opts, profiles.WithProfile(c.ProfileName)) - } else { - opts = append(opts, profiles.WithDefaultProfile()) + if !c.DisableEnv { + opts = append(opts, profiles.WithEnv()) } - if c.ProfileFile != "" { - opts = append(opts, profiles.WithFile(c.ProfileFile)) + if len(opts) == 0 { + return nil } p, err := profiles.Resolve(opts...) diff --git a/options/internaloptions/internaloptions_test.go b/options/internaloptions/internaloptions_test.go index 5d555cd..2948260 100644 --- a/options/internaloptions/internaloptions_test.go +++ b/options/internaloptions/internaloptions_test.go @@ -27,7 +27,7 @@ func isolateProfileEnv(t *testing.T) { for _, v := range []string{ "DATABRICKS_CONFIG_FILE", "DATABRICKS_CONFIG_PROFILE", "DATABRICKS_HOST", "DATABRICKS_TOKEN", "DATABRICKS_CLIENT_ID", "DATABRICKS_CLIENT_SECRET", - "DATABRICKS_AUTH_TYPE", + "DATABRICKS_AUTH_TYPE", "DATABRICKS_GROUP_ID", } { t.Setenv(v, "") } @@ -66,53 +66,141 @@ func TestClientOptionsResolve_PreservesProvidedLogger(t *testing.T) { } } -func TestClientOptionsResolve_DefaultCredentialsFromProfile(t *testing.T) { +func TestClientOptionsResolve_DefaultCredentialsFromEnabledSource(t *testing.T) { + const envToken = "dapi-env" + + testCases := []struct { + name string + configFileContents string + clientOptions ClientOptions + wantToken string + }{ + { + name: "config file without environment", + configFileContents: "[DEFAULT]\nhost = https://profile.example\ntoken = dapi-profile\n", + clientOptions: ClientOptions{DisableEnv: true}, + wantToken: "dapi-profile", + }, + { + name: "environment without config file", + clientOptions: ClientOptions{DisableConfigFile: true}, + wantToken: envToken, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + isolateProfileEnv(t) + t.Setenv("DATABRICKS_HOST", "https://env.example") + t.Setenv("DATABRICKS_TOKEN", envToken) + + options := tc.clientOptions + if tc.configFileContents != "" { + options.ConfigFile = writeConfigFile(t, tc.configFileContents) + } + if err := options.Resolve(); err != nil { + t.Fatalf("Resolve: %v", err) + } + if options.Credentials == nil { + t.Fatal("expected credentials to be resolved") + } + headers, err := options.Credentials.AuthHeaders(context.Background()) + if err != nil { + t.Fatalf("AuthHeaders: %v", err) + } + want := []auth.Header{{Key: "Authorization", Value: "Bearer " + tc.wantToken}} + if len(headers) != 1 || headers[0] != want[0] { + t.Errorf("AuthHeaders() = %v, want %v", headers, want) + } + }) + } +} + +func TestClientOptionsResolve_PreservesProvidedCredentials(t *testing.T) { isolateProfileEnv(t) path := writeConfigFile(t, "[DEFAULT]\nhost = https://workspace.example\ntoken = dapi-abc\n") - c := &ClientOptions{ProfileFile: path} + provided := stubCredentials{} + c := &ClientOptions{ConfigFile: path, Credentials: provided} if err := c.Resolve(); err != nil { t.Fatalf("Resolve: %v", err) } - if c.Credentials == nil { - t.Fatal("expected credentials to be resolved from the profile") - } - // The PAT strategy should have won, and its header should carry the token. - headers, err := c.Credentials.AuthHeaders(context.Background()) - if err != nil { - t.Fatalf("AuthHeaders: %v", err) - } - want := []auth.Header{{Key: "Authorization", Value: "Bearer dapi-abc"}} - if len(headers) != 1 || headers[0] != want[0] { - t.Errorf("AuthHeaders() = %v, want %v", headers, want) + if c.Credentials != auth.Credentials(provided) { + t.Error("expected explicitly provided credentials to be preserved") } } -func TestClientOptionsResolve_PreservesProvidedCredentials(t *testing.T) { +// TestClientOptionsResolve_PreservesProvidedCredentialsWithProfileGroupID +// verifies that profile group configuration does not affect explicitly supplied +// credentials. +func TestClientOptionsResolve_PreservesProvidedCredentialsWithProfileGroupID(t *testing.T) { isolateProfileEnv(t) - path := writeConfigFile(t, "[DEFAULT]\nhost = https://workspace.example\ntoken = dapi-abc\n") + + config := `[DEFAULT] +host = https://workspace.example +token = dapi-abc +group_id = profile-group +` + path := writeConfigFile(t, config) provided := stubCredentials{} - c := &ClientOptions{ProfileFile: path, Credentials: provided} + c := &ClientOptions{ConfigFile: path, Credentials: provided} + if err := c.Resolve(); err != nil { - t.Fatalf("Resolve: %v", err) + t.Fatalf("Resolve() error = %v", err) } + if c.Credentials != auth.Credentials(provided) { t.Error("expected explicitly provided credentials to be preserved") } } -func TestClientOptionsResolve_NoCredentialsWithoutProfileResolution(t *testing.T) { +func TestClientOptionsResolve_NoCredentialsWithoutAutomaticResolution(t *testing.T) { isolateProfileEnv(t) - c := &ClientOptions{DisableProfileResolution: true} + c := &ClientOptions{DisableConfigFile: true, DisableEnv: true} err := c.Resolve() if err == nil { t.Fatal("expected an error when no credentials are available and resolution is disabled") } } -func TestClientOptionsResolve_ProfilePrecedence(t *testing.T) { +func TestClientOptionsResolve_DisableConfigFileConflictsWithFileSelection(t *testing.T) { + const wantError = "cannot disable config file resolution when a config file or profile is specified" + + testCases := []struct { + name string + clientOptions ClientOptions + }{ + { + name: "config file", + clientOptions: ClientOptions{ + ConfigFile: "databrickscfg", + DisableConfigFile: true, + }, + }, + { + name: "profile", + clientOptions: ClientOptions{ + ProfileName: "workspace", + DisableConfigFile: true, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.clientOptions.Resolve() + if err == nil || err.Error() != wantError { + t.Errorf("Resolve() error = %v, want %q", err, wantError) + } + }) + } +} + +func TestClientOptionsResolve_SourcePrecedence(t *testing.T) { + const configFileContents = "[DEFAULT]\nhost = https://profile.example.com\naccount_id = profile-account\nworkspace_id = profile-workspace\n" + testCases := []struct { name string configFileContents string @@ -135,7 +223,7 @@ func TestClientOptionsResolve_ProfilePrecedence(t *testing.T) { }, { name: "environment overrides config file values", - configFileContents: "[DEFAULT]\nhost = https://profile.example.com\naccount_id = profile-account\nworkspace_id = profile-workspace\n", + configFileContents: configFileContents, envHost: "https://env.example.com", envAccountID: "env-account", envWorkspaceID: "env-workspace", @@ -158,12 +246,40 @@ func TestClientOptionsResolve_ProfilePrecedence(t *testing.T) { wantWorkspaceID: "explicit-workspace", }, { - name: "disabled profile resolution ignores environment", - envHost: "https://env.example.com", - envAccountID: "env-account", - envWorkspaceID: "env-workspace", + name: "disabled config file uses environment values", + configFileContents: configFileContents, + envHost: "https://env.example.com", + envAccountID: "env-account", + envWorkspaceID: "env-workspace", + clientOptions: ClientOptions{ + DisableConfigFile: true, + }, + wantHost: "https://env.example.com", + wantAccountID: "env-account", + wantWorkspaceID: "env-workspace", + }, + { + name: "disabled environment uses config file values", + configFileContents: configFileContents, + envHost: "https://env.example.com", + envAccountID: "env-account", + envWorkspaceID: "env-workspace", + clientOptions: ClientOptions{ + DisableEnv: true, + }, + wantHost: "https://profile.example.com", + wantAccountID: "profile-account", + wantWorkspaceID: "profile-workspace", + }, + { + name: "disabled config file and environment ignores both sources", + configFileContents: configFileContents, + envHost: "https://env.example.com", + envAccountID: "env-account", + envWorkspaceID: "env-workspace", clientOptions: ClientOptions{ - DisableProfileResolution: true, + DisableConfigFile: true, + DisableEnv: true, }, }, } @@ -180,7 +296,12 @@ func TestClientOptionsResolve_ProfilePrecedence(t *testing.T) { options := tc.clientOptions options.Credentials = stubCredentials{} if tc.configFileContents != "" { - options.ProfileFile = writeConfigFile(t, tc.configFileContents) + configFile := writeConfigFile(t, tc.configFileContents) + if options.DisableConfigFile { + t.Setenv("DATABRICKS_CONFIG_FILE", configFile) + } else { + options.ConfigFile = configFile + } } if err := options.Resolve(); err != nil { t.Fatalf("Resolve: %v", err) diff --git a/pipelines/CHANGELOG.md b/pipelines/CHANGELOG.md index 6224c04..19f237c 100644 --- a/pipelines/CHANGELOG.md +++ b/pipelines/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/pipelines/go.mod b/pipelines/go.mod index 52ca071..b471871 100644 --- a/pipelines/go.mod +++ b/pipelines/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/pipelines/internal/version.go b/pipelines/internal/version.go index b6f7e5b..634b50f 100644 --- a/pipelines/internal/version.go +++ b/pipelines/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-pipelines" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/pipelines/v2/client.go b/pipelines/v2/client.go old mode 100755 new mode 100644 index 1a9a9f4..4224448 --- a/pipelines/v2/client.go +++ b/pipelines/v2/client.go @@ -78,8 +78,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // * Applies the current pipeline environment onto the pipeline compute. The // environment applied can be used by subsequent dev-mode updates. -func (c *internalClient) ApplyEnvironment(ctx context.Context, req *ApplyEnvironmentRequest, opts ...call.Option) (*ApplyEnvironmentResponse, error) { - wireReq, err := applyEnvironmentRequestToWire(req) +func (c *internalClient) ApplyEnvironment(ctx context.Context, req ApplyEnvironmentRequest, opts ...call.Option) (*ApplyEnvironmentResponse, error) { + wireReq, err := applyEnvironmentRequestToWire(&req) if err != nil { return nil, err } @@ -100,7 +100,11 @@ func (c *internalClient) ApplyEnvironment(ctx context.Context, req *ApplyEnviron } pb := pathBuilder{} pb.literal("/api/2.0/pipelines/") - pb.singleSegment(*req.PipelineId) + if req.PipelineId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PipelineId) + } pb.literal("/environment/apply") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -144,8 +148,8 @@ func (c *internalClient) ApplyEnvironment(ctx context.Context, req *ApplyEnviron // Creates a new pipeline using Unity Catalog from a pipeline using Hive // Metastore. This method returns the ID of the newly created clone. // Additionally, this method starts an update for the newly created pipeline. -func (c *internalClient) Clone(ctx context.Context, req *ClonePipelineRequest, opts ...call.Option) (*ClonePipelineResponse, error) { - wireReq, err := clonePipelineRequestToWire(req) +func (c *internalClient) Clone(ctx context.Context, req ClonePipelineRequest, opts ...call.Option) (*ClonePipelineResponse, error) { + wireReq, err := clonePipelineRequestToWire(&req) if err != nil { return nil, err } @@ -166,7 +170,11 @@ func (c *internalClient) Clone(ctx context.Context, req *ClonePipelineRequest, o } pb := pathBuilder{} pb.literal("/api/2.0/pipelines/") - pb.singleSegment(*req.PipelineId) + if req.PipelineId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PipelineId) + } pb.literal("/clone") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -215,8 +223,8 @@ func (c *internalClient) Clone(ctx context.Context, req *ClonePipelineRequest, o // Creates a new data processing pipeline based on the requested configuration. // If successful, this method returns the ID of the new pipeline. -func (c *internalClient) Create(ctx context.Context, req *CreatePipelineRequest, opts ...call.Option) (*CreatePipelineResponse, error) { - wireReq, err := createPipelineRequestToWire(req) +func (c *internalClient) Create(ctx context.Context, req CreatePipelineRequest, opts ...call.Option) (*CreatePipelineResponse, error) { + wireReq, err := createPipelineRequestToWire(&req) if err != nil { return nil, err } @@ -283,8 +291,8 @@ func (c *internalClient) Create(ctx context.Context, req *CreatePipelineRequest, // Deletes a pipeline. If the pipeline publishes to Unity Catalog, pipeline // deletion will cascade to all pipeline tables. Please reach out to // support for assistance to undo this action. -func (c *internalClient) Delete(ctx context.Context, req *DeletePipelineRequest, opts ...call.Option) (*DeletePipelineResponse, error) { - wireReq, err := deletePipelineRequestToWire(req) +func (c *internalClient) Delete(ctx context.Context, req DeletePipelineRequest, opts ...call.Option) (*DeletePipelineResponse, error) { + wireReq, err := deletePipelineRequestToWire(&req) if err != nil { return nil, err } @@ -301,7 +309,11 @@ func (c *internalClient) Delete(ctx context.Context, req *DeletePipelineRequest, } pb := pathBuilder{} pb.literal("/api/2.0/pipelines/") - pb.singleSegment(*req.PipelineId) + if req.PipelineId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PipelineId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "force", wireReq.Force); err != nil { @@ -347,8 +359,8 @@ func (c *internalClient) Delete(ctx context.Context, req *DeletePipelineRequest, } // Updates a pipeline with the supplied configuration. -func (c *internalClient) Edit(ctx context.Context, req *EditPipelineRequest, opts ...call.Option) (*EditPipelineResponse, error) { - wireReq, err := editPipelineRequestToWire(req) +func (c *internalClient) Edit(ctx context.Context, req EditPipelineRequest, opts ...call.Option) (*EditPipelineResponse, error) { + wireReq, err := editPipelineRequestToWire(&req) if err != nil { return nil, err } @@ -369,7 +381,11 @@ func (c *internalClient) Edit(ctx context.Context, req *EditPipelineRequest, opt } pb := pathBuilder{} pb.literal("/api/2.0/pipelines/") - pb.singleSegment(*req.PipelineId) + if req.PipelineId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PipelineId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -410,8 +426,8 @@ func (c *internalClient) Edit(ctx context.Context, req *EditPipelineRequest, opt } // Retrieves events for a pipeline. -func (c *internalClient) Events(ctx context.Context, req *ListPipelineEventsRequest, opts ...call.Option) (*ListPipelineEventsResponse, error) { - wireReq, err := listPipelineEventsRequestToWire(req) +func (c *internalClient) Events(ctx context.Context, req ListPipelineEventsRequest, opts ...call.Option) (*ListPipelineEventsResponse, error) { + wireReq, err := listPipelineEventsRequestToWire(&req) if err != nil { return nil, err } @@ -428,7 +444,11 @@ func (c *internalClient) Events(ctx context.Context, req *ListPipelineEventsRequ } pb := pathBuilder{} pb.literal("/api/2.0/pipelines/") - pb.singleSegment(*req.PipelineId) + if req.PipelineId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PipelineId) + } pb.literal("/events") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -491,7 +511,7 @@ func (c *internalClient) Events(ctx context.Context, req *ListPipelineEventsRequ // // For example: // -// for item, err := range c.EventsIter(ctx, &ListPipelineEventsRequest{}) { +// for item, err := range c.EventsIter(ctx, ListPipelineEventsRequest{}) { // if err != nil { // return err // } @@ -503,16 +523,13 @@ func (c *internalClient) Events(ctx context.Context, req *ListPipelineEventsRequ // // Callers who need custom pagination logic should use // Events directly. -func (c *internalClient) EventsIter(ctx context.Context, req *ListPipelineEventsRequest, opts ...call.Option) iter.Seq2[*PipelineEvent, error] { +func (c *internalClient) EventsIter(ctx context.Context, req ListPipelineEventsRequest, opts ...call.Option) iter.Seq2[*PipelineEvent, error] { return func(yield func(*PipelineEvent, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListPipelineEventsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.Events(ctx, &pageReq, opts...) + resp, err := c.Events(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -531,7 +548,7 @@ func (c *internalClient) EventsIter(ctx context.Context, req *ListPipelineEvents } // Get a pipeline. -func (c *internalClient) Get(ctx context.Context, req *GetPipelineRequest, opts ...call.Option) (*GetPipelineResponse, error) { +func (c *internalClient) Get(ctx context.Context, req GetPipelineRequest, opts ...call.Option) (*GetPipelineResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -545,7 +562,11 @@ func (c *internalClient) Get(ctx context.Context, req *GetPipelineRequest, opts } pb := pathBuilder{} pb.literal("/api/2.0/pipelines/") - pb.singleSegment(*req.PipelineId) + if req.PipelineId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PipelineId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -591,7 +612,7 @@ func (c *internalClient) Get(ctx context.Context, req *GetPipelineRequest, opts } // Gets an update from an active pipeline. -func (c *internalClient) GetUpdate(ctx context.Context, req *GetUpdateRequest, opts ...call.Option) (*GetUpdateResponse, error) { +func (c *internalClient) GetUpdate(ctx context.Context, req GetUpdateRequest, opts ...call.Option) (*GetUpdateResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -605,9 +626,17 @@ func (c *internalClient) GetUpdate(ctx context.Context, req *GetUpdateRequest, o } pb := pathBuilder{} pb.literal("/api/2.0/pipelines/") - pb.singleSegment(*req.PipelineId) + if req.PipelineId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PipelineId) + } pb.literal("/updates/") - pb.singleSegment(*req.UpdateId) + if req.UpdateId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.UpdateId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -653,8 +682,8 @@ func (c *internalClient) GetUpdate(ctx context.Context, req *GetUpdateRequest, o } // Lists pipelines defined in the Spark Declarative Pipelines system. -func (c *internalClient) List(ctx context.Context, req *ListPipelinesRequest, opts ...call.Option) (*ListPipelinesResponse, error) { - wireReq, err := listPipelinesRequestToWire(req) +func (c *internalClient) List(ctx context.Context, req ListPipelinesRequest, opts ...call.Option) (*ListPipelinesResponse, error) { + wireReq, err := listPipelinesRequestToWire(&req) if err != nil { return nil, err } @@ -730,7 +759,7 @@ func (c *internalClient) List(ctx context.Context, req *ListPipelinesRequest, op // // For example: // -// for item, err := range c.ListIter(ctx, &ListPipelinesRequest{}) { +// for item, err := range c.ListIter(ctx, ListPipelinesRequest{}) { // if err != nil { // return err // } @@ -742,16 +771,13 @@ func (c *internalClient) List(ctx context.Context, req *ListPipelinesRequest, op // // Callers who need custom pagination logic should use // List directly. -func (c *internalClient) ListIter(ctx context.Context, req *ListPipelinesRequest, opts ...call.Option) iter.Seq2[*PipelineStateInfo, error] { +func (c *internalClient) ListIter(ctx context.Context, req ListPipelinesRequest, opts ...call.Option) iter.Seq2[*PipelineStateInfo, error] { return func(yield func(*PipelineStateInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListPipelinesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.List(ctx, &pageReq, opts...) + resp, err := c.List(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -770,8 +796,8 @@ func (c *internalClient) ListIter(ctx context.Context, req *ListPipelinesRequest } // List updates for an active pipeline. -func (c *internalClient) ListUpdates(ctx context.Context, req *ListUpdatesRequest, opts ...call.Option) (*ListUpdatesResponse, error) { - wireReq, err := listUpdatesRequestToWire(req) +func (c *internalClient) ListUpdates(ctx context.Context, req ListUpdatesRequest, opts ...call.Option) (*ListUpdatesResponse, error) { + wireReq, err := listUpdatesRequestToWire(&req) if err != nil { return nil, err } @@ -788,7 +814,11 @@ func (c *internalClient) ListUpdates(ctx context.Context, req *ListUpdatesReques } pb := pathBuilder{} pb.literal("/api/2.0/pipelines/") - pb.singleSegment(*req.PipelineId) + if req.PipelineId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PipelineId) + } pb.literal("/updates") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -846,8 +876,8 @@ func (c *internalClient) ListUpdates(ctx context.Context, req *ListUpdatesReques // Starts a new update for the pipeline. If there is already an active update // for the pipeline, the request will fail and the active update will remain // running. -func (c *internalClient) Start(ctx context.Context, req *StartUpdateRequest, opts ...call.Option) (*StartUpdateResponse, error) { - wireReq, err := startUpdateRequestToWire(req) +func (c *internalClient) Start(ctx context.Context, req StartUpdateRequest, opts ...call.Option) (*StartUpdateResponse, error) { + wireReq, err := startUpdateRequestToWire(&req) if err != nil { return nil, err } @@ -868,7 +898,11 @@ func (c *internalClient) Start(ctx context.Context, req *StartUpdateRequest, opt } pb := pathBuilder{} pb.literal("/api/2.0/pipelines/") - pb.singleSegment(*req.PipelineId) + if req.PipelineId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PipelineId) + } pb.literal("/updates") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -917,8 +951,8 @@ func (c *internalClient) Start(ctx context.Context, req *StartUpdateRequest, opt // Stops the pipeline by canceling the active update. If there is no active // update for the pipeline, this request is a no-op. -func (c *internalClient) stopBase(ctx context.Context, req *StopPipelineRequest, opts ...call.Option) (*StopPipelineResponse, error) { - wireReq, err := stopPipelineRequestToWire(req) +func (c *internalClient) stopBase(ctx context.Context, req StopPipelineRequest, opts ...call.Option) (*StopPipelineResponse, error) { + wireReq, err := stopPipelineRequestToWire(&req) if err != nil { return nil, err } @@ -939,7 +973,11 @@ func (c *internalClient) stopBase(ctx context.Context, req *StopPipelineRequest, } pb := pathBuilder{} pb.literal("/api/2.0/pipelines/") - pb.singleSegment(*req.PipelineId) + if req.PipelineId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PipelineId) + } pb.literal("/stop") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -982,7 +1020,7 @@ func (c *internalClient) stopBase(ctx context.Context, req *StopPipelineRequest, // Stops the pipeline by canceling the active update. If there is no active // update for the pipeline, this request is a no-op. -func (c *internalClient) Stop(ctx context.Context, req *StopPipelineRequest, opts ...call.Option) (*StopWaiter, error) { +func (c *internalClient) Stop(ctx context.Context, req StopPipelineRequest, opts ...call.Option) (*StopWaiter, error) { if req.PipelineId == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "PipelineId") } @@ -999,13 +1037,18 @@ func (c *internalClient) Stop(ctx context.Context, req *StopPipelineRequest, opt // StopWaiter tracks the state of the operation started by Stop. type StopWaiter struct { - poll func(context.Context, *GetPipelineRequest, ...call.Option) (*GetPipelineResponse, error) + poll func(context.Context, GetPipelineRequest, ...call.Option) (*GetPipelineResponse, error) pipelineId string } +// GetPipelineId returns the PipelineId value used to identify the operation. +func (w *StopWaiter) GetPipelineId() string { + return w.pipelineId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *StopWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetPipelineRequest{ + pollResp, err := w.poll(ctx, GetPipelineRequest{ PipelineId: &w.pipelineId, }, opts...) if err != nil { @@ -1030,7 +1073,7 @@ func (w *StopWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error func (w *StopWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GetPipelineResponse, error) { var result *GetPipelineResponse poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetPipelineRequest{ + pollResp, err := w.poll(ctx, GetPipelineRequest{ PipelineId: &w.pipelineId, }) if err != nil { diff --git a/pipelines/v2/genhelper.go b/pipelines/v2/genhelper.go old mode 100755 new mode 100644 index 275146b..81f017c --- a/pipelines/v2/genhelper.go +++ b/pipelines/v2/genhelper.go @@ -199,11 +199,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -216,13 +217,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/pipelines/v2/model.go b/pipelines/v2/model.go old mode 100755 new mode 100644 index 565db34..37b3e4c --- a/pipelines/v2/model.go +++ b/pipelines/v2/model.go @@ -86,6 +86,7 @@ const ( IngestionSourceType_Confluence IngestionSourceType = "CONFLUENCE" IngestionSourceType_MetaMarketing IngestionSourceType = "META_MARKETING" IngestionSourceType_Zendesk IngestionSourceType = "ZENDESK" + IngestionSourceType_Rabbitmq IngestionSourceType = "RABBITMQ" IngestionSourceType_ForeignCatalog IngestionSourceType = "FOREIGN_CATALOG" ) @@ -633,6 +634,13 @@ type ConnectorOptions_ConnectorOptions_KafkaOptions struct { func (*ConnectorOptions_ConnectorOptions_KafkaOptions) isConnectorOptions_ConnectorOptions() {} +// ConnectorOptions_ConnectorOptions_RabbitmqOptions selects RabbitmqOptions for ConnectorOptions.ConnectorOptions. +type ConnectorOptions_ConnectorOptions_RabbitmqOptions struct { + RabbitmqOptions RabbitmqOptions +} + +func (*ConnectorOptions_ConnectorOptions_RabbitmqOptions) isConnectorOptions_ConnectorOptions() {} + // ConnectorOptions_ConnectorOptions_MarketoOptions selects MarketoOptions for ConnectorOptions.ConnectorOptions. type ConnectorOptions_ConnectorOptions_MarketoOptions struct { MarketoOptions MarketoOptions @@ -1267,12 +1275,10 @@ type IngestionPipelineDefinition_ReportSpec struct { type IngestionPipelineDefinition_SchemaSpec struct { // The source catalog name. Might be optional depending on the type of source. SourceCatalog *string - // Schema name in the source database. Currently required; this field will - // become optional in an upcoming release, since some source types (for example - // streaming / message-bus connectors) do not use it. When that change ships, - // this field's type in the generated SDKs and CLI will change from required to - // optional (nullable); clients that assume it is always present should handle - // its absence. + // Schema name in the source database. Optional: some source types (for example + // streaming or message-bus connectors) do not use it, so it may be absent from + // a pipeline's definition. Clients that assume it is always present should + // handle its absence. SourceSchema *string // Required. Destination catalog to store tables. DestinationCatalog *string @@ -1299,12 +1305,10 @@ type IngestionPipelineDefinition_TableSpec struct { // Schema name in the source database. Might be optional depending on the type // of source. SourceSchema *string - // Table name in the source database. Currently required; this field will become - // optional in an upcoming release, since some source types (for example - // streaming / message-bus connectors) do not use it. When that change ships, - // this field's type in the generated SDKs and CLI will change from required to - // optional (nullable); clients that assume it is always present should handle - // its absence. + // Table name in the source database. Optional: some source types (for example + // streaming or message-bus connectors) do not use it, so it may be absent from + // a pipeline's definition. Clients that assume it is always present should + // handle its absence. SourceTable *string // Required. Destination catalog to store table. DestinationCatalog *string @@ -1819,8 +1823,9 @@ type PathPattern struct { type PipelineCluster struct { // A label for the cluster specification, either `default` to configure the - // default cluster, or `maintenance` to configure the maintenance cluster. This - // field is optional. The default value is `default`. + // default cluster settings applied to both the update and maintenance clusters, + // `updates` to configure the update cluster, or `maintenance` to configure the + // maintenance cluster. This field is optional. The default value is `default`. Label *string // Note: This field won't be persisted. Only API users will check this field. ApplyPolicyDefaultValues *bool @@ -2475,6 +2480,15 @@ type PostgresSlotConfig struct { PublicationName *string } +// RabbitMQ specific options for ingestion. Performance tuning options +// (consumers_per_task, max_messages_per_fetch, etc.) are intentionally not +// exposed in the public API. The managed connector uses sensible defaults +// internally. These can be added later if user demand arises.. +type RabbitmqOptions struct { + // (Required) RabbitMQ queue name to consume from. + Queue *string +} + // Reddit Ads specific options for ingestion. type RedditAdsOptions struct { // (Optional) Start date for the initial sync of report tables in YYYY-MM-DD diff --git a/pipelines/v2/wire.go b/pipelines/v2/wire.go old mode 100755 new mode 100644 index d3d3720..ba246ea --- a/pipelines/v2/wire.go +++ b/pipelines/v2/wire.go @@ -3,9 +3,55 @@ package pipelines import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type apiSourceConnectorConfigWire struct { Configs map[string]string `json:"configs,omitempty"` } @@ -90,7 +136,7 @@ func autoFullRefreshPolicyFromWire(w *autoFullRefreshPolicyWire) (*AutoFullRefre type clonePipelineRequestWire struct { PipelineId *string `json:"pipeline_id,omitempty"` - ExpectedLastModified *int64 `json:"expected_last_modified,omitempty"` + ExpectedLastModified *wireInt64 `json:"expected_last_modified,omitempty"` AllowDuplicateNames *bool `json:"allow_duplicate_names,omitempty"` Id *string `json:"id,omitempty"` Name *string `json:"name,omitempty"` @@ -128,6 +174,10 @@ func clonePipelineRequestToWire(v *ClonePipelineRequest) (*clonePipelineRequestW if v == nil { return nil, nil } + expectedLastModifiedWireValue, err := int64ToWire(v.ExpectedLastModified) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ClonePipelineRequest.ExpectedLastModified", err) + } clustersWireValue, err := convertSlice(v.Clusters, pipelineClusterToWire) if err != nil { return nil, fmt.Errorf("%s: %w", "ClonePipelineRequest.Clusters", err) @@ -174,7 +224,7 @@ func clonePipelineRequestToWire(v *ClonePipelineRequest) (*clonePipelineRequestW } return &clonePipelineRequestWire{ PipelineId: v.PipelineId, - ExpectedLastModified: v.ExpectedLastModified, + ExpectedLastModified: expectedLastModifiedWireValue, AllowDuplicateNames: v.AllowDuplicateNames, Id: v.Id, Name: v.Name, @@ -278,6 +328,7 @@ type connectorOptionsWire struct { MetaAdsOptions *metaMarketingOptionsWire `json:"meta_ads_options,omitempty"` ZendeskSupportOptions *zendeskSupportOptionsWire `json:"zendesk_support_options,omitempty"` KafkaOptions *kafkaOptionsWire `json:"kafka_options,omitempty"` + RabbitmqOptions *rabbitmqOptionsWire `json:"rabbitmq_options,omitempty"` MarketoOptions *marketoOptionsWire `json:"marketo_options,omitempty"` LinkedinAdsOptions *linkedInAdsOptionsWire `json:"linkedin_ads_options,omitempty"` RedditAdsOptions *redditAdsOptionsWire `json:"reddit_ads_options,omitempty"` @@ -299,6 +350,7 @@ func connectorOptionsToWire(v *ConnectorOptions) (*connectorOptionsWire, error) var connectorOptionsMetaAdsOptionsWire *metaMarketingOptionsWire var connectorOptionsZendeskSupportOptionsWire *zendeskSupportOptionsWire var connectorOptionsKafkaOptionsWire *kafkaOptionsWire + var connectorOptionsRabbitmqOptionsWire *rabbitmqOptionsWire var connectorOptionsMarketoOptionsWire *marketoOptionsWire var connectorOptionsLinkedinAdsOptionsWire *linkedInAdsOptionsWire var connectorOptionsRedditAdsOptionsWire *redditAdsOptionsWire @@ -393,6 +445,14 @@ func connectorOptionsToWire(v *ConnectorOptions) (*connectorOptionsWire, error) } connectorOptionsKafkaOptionsWire = connectorOptionsKafkaOptionsConverted } + case *ConnectorOptions_ConnectorOptions_RabbitmqOptions: + if value != nil { + connectorOptionsRabbitmqOptionsConverted, err := rabbitmqOptionsToWire(&value.RabbitmqOptions) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ConnectorOptions.ConnectorOptions.RabbitmqOptions", err) + } + connectorOptionsRabbitmqOptionsWire = connectorOptionsRabbitmqOptionsConverted + } case *ConnectorOptions_ConnectorOptions_MarketoOptions: if value != nil { connectorOptionsMarketoOptionsConverted, err := marketoOptionsToWire(&value.MarketoOptions) @@ -440,6 +500,7 @@ func connectorOptionsToWire(v *ConnectorOptions) (*connectorOptionsWire, error) MetaAdsOptions: connectorOptionsMetaAdsOptionsWire, ZendeskSupportOptions: connectorOptionsZendeskSupportOptionsWire, KafkaOptions: connectorOptionsKafkaOptionsWire, + RabbitmqOptions: connectorOptionsRabbitmqOptionsWire, MarketoOptions: connectorOptionsMarketoOptionsWire, LinkedinAdsOptions: connectorOptionsLinkedinAdsOptionsWire, RedditAdsOptions: connectorOptionsRedditAdsOptionsWire, @@ -485,6 +546,9 @@ func connectorOptionsFromWire(w *connectorOptionsWire) (*ConnectorOptions, error if w.KafkaOptions != nil { connectorOptionsMembers++ } + if w.RabbitmqOptions != nil { + connectorOptionsMembers++ + } if w.MarketoOptions != nil { connectorOptionsMembers++ } @@ -568,6 +632,12 @@ func connectorOptionsFromWire(w *connectorOptionsWire) (*ConnectorOptions, error return nil, fmt.Errorf("%s: %w", "ConnectorOptions.ConnectorOptions.KafkaOptions", err) } connectorOptionsSelection = &ConnectorOptions_ConnectorOptions_KafkaOptions{KafkaOptions: *connectorOptionsKafkaOptionsConverted} + case w.RabbitmqOptions != nil: + connectorOptionsRabbitmqOptionsConverted, err := rabbitmqOptionsFromWire(w.RabbitmqOptions) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ConnectorOptions.ConnectorOptions.RabbitmqOptions", err) + } + connectorOptionsSelection = &ConnectorOptions_ConnectorOptions_RabbitmqOptions{RabbitmqOptions: *connectorOptionsRabbitmqOptionsConverted} case w.MarketoOptions != nil: connectorOptionsMarketoOptionsConverted, err := marketoOptionsFromWire(w.MarketoOptions) if err != nil { @@ -768,17 +838,21 @@ func cronTriggerFromWire(w *cronTriggerWire) (*CronTrigger, error) { } type dataPlaneIdWire struct { - Instance *string `json:"instance,omitempty"` - SeqNo *int64 `json:"seq_no,omitempty"` + Instance *string `json:"instance,omitempty"` + SeqNo *wireInt64 `json:"seq_no,omitempty"` } func dataPlaneIdFromWire(w *dataPlaneIdWire) (*DataPlaneId, error) { if w == nil { return nil, nil } + seqNoPublicValue, err := int64FromWire(w.SeqNo) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DataPlaneId.SeqNo", err) + } return &DataPlaneId{ Instance: w.Instance, - SeqNo: w.SeqNo, + SeqNo: seqNoPublicValue, }, nil } @@ -830,7 +904,7 @@ func deletePipelineRequestToWire(v *DeletePipelineRequest) (*deletePipelineReque type editPipelineRequestWire struct { PipelineId *string `json:"pipeline_id,omitempty"` AllowDuplicateNames *bool `json:"allow_duplicate_names,omitempty"` - ExpectedLastModified *int64 `json:"expected_last_modified,omitempty"` + ExpectedLastModified *wireInt64 `json:"expected_last_modified,omitempty"` RunAs *pipelinesJobRunAsWire `json:"run_as,omitempty"` Parameters map[string]string `json:"parameters,omitempty"` Id *string `json:"id,omitempty"` @@ -868,6 +942,10 @@ func editPipelineRequestToWire(v *EditPipelineRequest) (*editPipelineRequestWire if v == nil { return nil, nil } + expectedLastModifiedWireValue, err := int64ToWire(v.ExpectedLastModified) + if err != nil { + return nil, fmt.Errorf("%s: %w", "EditPipelineRequest.ExpectedLastModified", err) + } runAsWireValue, err := pipelinesJobRunAsToWire(v.RunAs) if err != nil { return nil, fmt.Errorf("%s: %w", "EditPipelineRequest.RunAs", err) @@ -919,7 +997,7 @@ func editPipelineRequestToWire(v *EditPipelineRequest) (*editPipelineRequestWire return &editPipelineRequestWire{ PipelineId: v.PipelineId, AllowDuplicateNames: v.AllowDuplicateNames, - ExpectedLastModified: v.ExpectedLastModified, + ExpectedLastModified: expectedLastModifiedWireValue, RunAs: runAsWireValue, Parameters: v.Parameters, Id: v.Id, @@ -1164,7 +1242,7 @@ type getPipelineResponseWire struct { Health PipelineHealthStatus `json:"health,omitempty"` CreatorUserName *string `json:"creator_user_name,omitempty"` LatestUpdates []updateStateInfoWire `json:"latest_updates,omitempty"` - LastModified *int64 `json:"last_modified,omitempty"` + LastModified *wireInt64 `json:"last_modified,omitempty"` RunAsUserName *string `json:"run_as_user_name,omitempty"` EffectiveBudgetPolicyId *string `json:"effective_budget_policy_id,omitempty"` EffectivePublishingMode PublishingMode `json:"effective_publishing_mode,omitempty"` @@ -1185,6 +1263,10 @@ func getPipelineResponseFromWire(w *getPipelineResponseWire) (*GetPipelineRespon if err != nil { return nil, fmt.Errorf("%s: %w", "GetPipelineResponse.LatestUpdates", err) } + lastModifiedPublicValue, err := int64FromWire(w.LastModified) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetPipelineResponse.LastModified", err) + } runAsPublicValue, err := pipelinesJobRunAsFromWire(w.RunAs) if err != nil { return nil, fmt.Errorf("%s: %w", "GetPipelineResponse.RunAs", err) @@ -1199,7 +1281,7 @@ func getPipelineResponseFromWire(w *getPipelineResponseWire) (*GetPipelineRespon Health: w.Health, CreatorUserName: w.CreatorUserName, LatestUpdates: latestUpdatesPublicValue, - LastModified: w.LastModified, + LastModified: lastModifiedPublicValue, RunAsUserName: w.RunAsUserName, EffectiveBudgetPolicyId: w.EffectiveBudgetPolicyId, EffectivePublishingMode: w.EffectivePublishingMode, @@ -1907,19 +1989,23 @@ func ingestionPipelineDefinition_TableSpecificConfigFromWire(w *ingestionPipelin } type ingestionPipelineDefinition_TableSpecificConfig_QueryBasedConnectorConfigWire struct { - CursorColumns []string `json:"cursor_columns,omitempty"` - DeletionCondition *string `json:"deletion_condition,omitempty"` - HardDeletionSyncMinIntervalInSeconds *int64 `json:"hard_deletion_sync_min_interval_in_seconds,omitempty"` + CursorColumns []string `json:"cursor_columns,omitempty"` + DeletionCondition *string `json:"deletion_condition,omitempty"` + HardDeletionSyncMinIntervalInSeconds *wireInt64 `json:"hard_deletion_sync_min_interval_in_seconds,omitempty"` } func ingestionPipelineDefinition_TableSpecificConfig_QueryBasedConnectorConfigToWire(v *IngestionPipelineDefinition_TableSpecificConfig_QueryBasedConnectorConfig) (*ingestionPipelineDefinition_TableSpecificConfig_QueryBasedConnectorConfigWire, error) { if v == nil { return nil, nil } + hardDeletionSyncMinIntervalInSecondsWireValue, err := int64ToWire(v.HardDeletionSyncMinIntervalInSeconds) + if err != nil { + return nil, fmt.Errorf("%s: %w", "IngestionPipelineDefinition_TableSpecificConfig_QueryBasedConnectorConfig.HardDeletionSyncMinIntervalInSeconds", err) + } return &ingestionPipelineDefinition_TableSpecificConfig_QueryBasedConnectorConfigWire{ CursorColumns: v.CursorColumns, DeletionCondition: v.DeletionCondition, - HardDeletionSyncMinIntervalInSeconds: v.HardDeletionSyncMinIntervalInSeconds, + HardDeletionSyncMinIntervalInSeconds: hardDeletionSyncMinIntervalInSecondsWireValue, }, nil } @@ -1927,10 +2013,14 @@ func ingestionPipelineDefinition_TableSpecificConfig_QueryBasedConnectorConfigFr if w == nil { return nil, nil } + hardDeletionSyncMinIntervalInSecondsPublicValue, err := int64FromWire(w.HardDeletionSyncMinIntervalInSeconds) + if err != nil { + return nil, fmt.Errorf("%s: %w", "IngestionPipelineDefinition_TableSpecificConfig_QueryBasedConnectorConfig.HardDeletionSyncMinIntervalInSeconds", err) + } return &IngestionPipelineDefinition_TableSpecificConfig_QueryBasedConnectorConfig{ CursorColumns: w.CursorColumns, DeletionCondition: w.DeletionCondition, - HardDeletionSyncMinIntervalInSeconds: w.HardDeletionSyncMinIntervalInSeconds, + HardDeletionSyncMinIntervalInSeconds: hardDeletionSyncMinIntervalInSecondsPublicValue, }, nil } @@ -2057,7 +2147,7 @@ type kafkaOptionsWire struct { KeyTransformer *transformerWire `json:"key_transformer,omitempty"` ValueTransformer *transformerWire `json:"value_transformer,omitempty"` StartingOffset *string `json:"starting_offset,omitempty"` - MaxOffsetsPerTrigger *int64 `json:"max_offsets_per_trigger,omitempty"` + MaxOffsetsPerTrigger *wireInt64 `json:"max_offsets_per_trigger,omitempty"` ClientConfig map[string]string `json:"client_config,omitempty"` } @@ -2073,13 +2163,17 @@ func kafkaOptionsToWire(v *KafkaOptions) (*kafkaOptionsWire, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "KafkaOptions.ValueTransformer", err) } + maxOffsetsPerTriggerWireValue, err := int64ToWire(v.MaxOffsetsPerTrigger) + if err != nil { + return nil, fmt.Errorf("%s: %w", "KafkaOptions.MaxOffsetsPerTrigger", err) + } return &kafkaOptionsWire{ Topics: v.Topics, TopicPattern: v.TopicPattern, KeyTransformer: keyTransformerWireValue, ValueTransformer: valueTransformerWireValue, StartingOffset: v.StartingOffset, - MaxOffsetsPerTrigger: v.MaxOffsetsPerTrigger, + MaxOffsetsPerTrigger: maxOffsetsPerTriggerWireValue, ClientConfig: v.ClientConfig, }, nil } @@ -2096,13 +2190,17 @@ func kafkaOptionsFromWire(w *kafkaOptionsWire) (*KafkaOptions, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "KafkaOptions.ValueTransformer", err) } + maxOffsetsPerTriggerPublicValue, err := int64FromWire(w.MaxOffsetsPerTrigger) + if err != nil { + return nil, fmt.Errorf("%s: %w", "KafkaOptions.MaxOffsetsPerTrigger", err) + } return &KafkaOptions{ Topics: w.Topics, TopicPattern: w.TopicPattern, KeyTransformer: keyTransformerPublicValue, ValueTransformer: valueTransformerPublicValue, StartingOffset: w.StartingOffset, - MaxOffsetsPerTrigger: w.MaxOffsetsPerTrigger, + MaxOffsetsPerTrigger: maxOffsetsPerTriggerPublicValue, ClientConfig: w.ClientConfig, }, nil } @@ -2500,38 +2598,46 @@ func operationTimeWindowFromWire(w *operationTimeWindowWire) (*OperationTimeWind } type originWire struct { - Cloud *string `json:"cloud,omitempty"` - Region *string `json:"region,omitempty"` - OrgId *int64 `json:"org_id,omitempty"` - PipelineId *string `json:"pipeline_id,omitempty"` - PipelineName *string `json:"pipeline_name,omitempty"` - ClusterId *string `json:"cluster_id,omitempty"` - UpdateId *string `json:"update_id,omitempty"` - MaintenanceId *string `json:"maintenance_id,omitempty"` - TableId *string `json:"table_id,omitempty"` - DatasetName *string `json:"dataset_name,omitempty"` - FlowId *string `json:"flow_id,omitempty"` - FlowName *string `json:"flow_name,omitempty"` - BatchId *int64 `json:"batch_id,omitempty"` - RequestId *string `json:"request_id,omitempty"` - UcResourceId *string `json:"uc_resource_id,omitempty"` - Host *string `json:"host,omitempty"` - MaterializationName *string `json:"materialization_name,omitempty"` - IngestionSourceConnectionName *string `json:"ingestion_source_connection_name,omitempty"` - IngestionSourceCatalogName *string `json:"ingestion_source_catalog_name,omitempty"` - IngestionSourceSchemaName *string `json:"ingestion_source_schema_name,omitempty"` - IngestionSourceTableName *string `json:"ingestion_source_table_name,omitempty"` - IngestionSourceTableVersion *string `json:"ingestion_source_table_version,omitempty"` + Cloud *string `json:"cloud,omitempty"` + Region *string `json:"region,omitempty"` + OrgId *wireInt64 `json:"org_id,omitempty"` + PipelineId *string `json:"pipeline_id,omitempty"` + PipelineName *string `json:"pipeline_name,omitempty"` + ClusterId *string `json:"cluster_id,omitempty"` + UpdateId *string `json:"update_id,omitempty"` + MaintenanceId *string `json:"maintenance_id,omitempty"` + TableId *string `json:"table_id,omitempty"` + DatasetName *string `json:"dataset_name,omitempty"` + FlowId *string `json:"flow_id,omitempty"` + FlowName *string `json:"flow_name,omitempty"` + BatchId *wireInt64 `json:"batch_id,omitempty"` + RequestId *string `json:"request_id,omitempty"` + UcResourceId *string `json:"uc_resource_id,omitempty"` + Host *string `json:"host,omitempty"` + MaterializationName *string `json:"materialization_name,omitempty"` + IngestionSourceConnectionName *string `json:"ingestion_source_connection_name,omitempty"` + IngestionSourceCatalogName *string `json:"ingestion_source_catalog_name,omitempty"` + IngestionSourceSchemaName *string `json:"ingestion_source_schema_name,omitempty"` + IngestionSourceTableName *string `json:"ingestion_source_table_name,omitempty"` + IngestionSourceTableVersion *string `json:"ingestion_source_table_version,omitempty"` } func originFromWire(w *originWire) (*Origin, error) { if w == nil { return nil, nil } + orgIdPublicValue, err := int64FromWire(w.OrgId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Origin.OrgId", err) + } + batchIdPublicValue, err := int64FromWire(w.BatchId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Origin.BatchId", err) + } return &Origin{ Cloud: w.Cloud, Region: w.Region, - OrgId: w.OrgId, + OrgId: orgIdPublicValue, PipelineId: w.PipelineId, PipelineName: w.PipelineName, ClusterId: w.ClusterId, @@ -2541,7 +2647,7 @@ func originFromWire(w *originWire) (*Origin, error) { DatasetName: w.DatasetName, FlowId: w.FlowId, FlowName: w.FlowName, - BatchId: w.BatchId, + BatchId: batchIdPublicValue, RequestId: w.RequestId, UcResourceId: w.UcResourceId, Host: w.Host, @@ -3699,6 +3805,28 @@ func postgresSlotConfigFromWire(w *postgresSlotConfigWire) (*PostgresSlotConfig, }, nil } +type rabbitmqOptionsWire struct { + Queue *string `json:"queue,omitempty"` +} + +func rabbitmqOptionsToWire(v *RabbitmqOptions) (*rabbitmqOptionsWire, error) { + if v == nil { + return nil, nil + } + return &rabbitmqOptionsWire{ + Queue: v.Queue, + }, nil +} + +func rabbitmqOptionsFromWire(w *rabbitmqOptionsWire) (*RabbitmqOptions, error) { + if w == nil { + return nil, nil + } + return &RabbitmqOptions{ + Queue: w.Queue, + }, nil +} + type redditAdsOptionsWire struct { SyncStartDate *string `json:"sync_start_date,omitempty"` LookbackWindowDays *int `json:"lookback_window_days,omitempty"` @@ -3843,7 +3971,7 @@ func rewindSpecToWire(v *RewindSpec) (*rewindSpecWire, error) { type sequencingWire struct { DataPlaneId *dataPlaneIdWire `json:"data_plane_id,omitempty"` - ControlPlaneSeqNo *int64 `json:"control_plane_seq_no,omitempty"` + ControlPlaneSeqNo *wireInt64 `json:"control_plane_seq_no,omitempty"` } func sequencingFromWire(w *sequencingWire) (*Sequencing, error) { @@ -3854,9 +3982,13 @@ func sequencingFromWire(w *sequencingWire) (*Sequencing, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "Sequencing.DataPlaneId", err) } + controlPlaneSeqNoPublicValue, err := int64FromWire(w.ControlPlaneSeqNo) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Sequencing.ControlPlaneSeqNo", err) + } return &Sequencing{ DataPlaneId: dataPlaneIdPublicValue, - ControlPlaneSeqNo: w.ControlPlaneSeqNo, + ControlPlaneSeqNo: controlPlaneSeqNoPublicValue, }, nil } @@ -4344,7 +4476,7 @@ type updateInfoWire struct { Cause UpdateCause `json:"cause,omitempty"` State UpdateState `json:"state,omitempty"` ClusterId *string `json:"cluster_id,omitempty"` - CreationTime *int64 `json:"creation_time,omitempty"` + CreationTime *wireInt64 `json:"creation_time,omitempty"` FullRefresh *bool `json:"full_refresh,omitempty"` RefreshSelection []string `json:"refresh_selection,omitempty"` FullRefreshSelection []string `json:"full_refresh_selection,omitempty"` @@ -4361,6 +4493,10 @@ func updateInfoFromWire(w *updateInfoWire) (*UpdateInfo, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateInfo.Config", err) } + creationTimePublicValue, err := int64FromWire(w.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateInfo.CreationTime", err) + } return &UpdateInfo{ PipelineId: w.PipelineId, UpdateId: w.UpdateId, @@ -4368,7 +4504,7 @@ func updateInfoFromWire(w *updateInfoWire) (*UpdateInfo, error) { Cause: w.Cause, State: w.State, ClusterId: w.ClusterId, - CreationTime: w.CreationTime, + CreationTime: creationTimePublicValue, FullRefresh: w.FullRefresh, RefreshSelection: w.RefreshSelection, FullRefreshSelection: w.FullRefreshSelection, diff --git a/policyfamilies/CHANGELOG.md b/policyfamilies/CHANGELOG.md index 6224c04..19f237c 100644 --- a/policyfamilies/CHANGELOG.md +++ b/policyfamilies/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/policyfamilies/go.mod b/policyfamilies/go.mod index 4cac7d2..ffbafde 100644 --- a/policyfamilies/go.mod +++ b/policyfamilies/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/policyfamilies/internal/version.go b/policyfamilies/internal/version.go index af6b259..2441d58 100644 --- a/policyfamilies/internal/version.go +++ b/policyfamilies/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-policyfamilies" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/policyfamilies/v2/client.go b/policyfamilies/v2/client.go old mode 100755 new mode 100644 index 22fd427..f33517f --- a/policyfamilies/v2/client.go +++ b/policyfamilies/v2/client.go @@ -75,8 +75,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Retrieve the information for an policy family based on its identifier and // version -func (c *internalClient) GetPolicyFamily(ctx context.Context, req *GetPolicyFamilyRequest, opts ...call.Option) (*PolicyFamily, error) { - wireReq, err := getPolicyFamilyRequestToWire(req) +func (c *internalClient) GetPolicyFamily(ctx context.Context, req GetPolicyFamilyRequest, opts ...call.Option) (*PolicyFamily, error) { + wireReq, err := getPolicyFamilyRequestToWire(&req) if err != nil { return nil, err } @@ -93,7 +93,11 @@ func (c *internalClient) GetPolicyFamily(ctx context.Context, req *GetPolicyFami } pb := pathBuilder{} pb.literal("/api/2.0/policy-families/") - pb.singleSegment(*req.PolicyFamilyId) + if req.PolicyFamilyId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.PolicyFamilyId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "version", wireReq.Version); err != nil { @@ -143,8 +147,8 @@ func (c *internalClient) GetPolicyFamily(ctx context.Context, req *GetPolicyFami // Returns the list of policy definition types available to use at their latest // version. This API is paginated. -func (c *internalClient) ListPolicyFamilies(ctx context.Context, req *ListPolicyFamiliesRequest, opts ...call.Option) (*ListPolicyFamiliesResponse, error) { - wireReq, err := listPolicyFamiliesRequestToWire(req) +func (c *internalClient) ListPolicyFamilies(ctx context.Context, req ListPolicyFamiliesRequest, opts ...call.Option) (*ListPolicyFamiliesResponse, error) { + wireReq, err := listPolicyFamiliesRequestToWire(&req) if err != nil { return nil, err } @@ -214,7 +218,7 @@ func (c *internalClient) ListPolicyFamilies(ctx context.Context, req *ListPolicy // // For example: // -// for item, err := range c.ListPolicyFamiliesIter(ctx, &ListPolicyFamiliesRequest{}) { +// for item, err := range c.ListPolicyFamiliesIter(ctx, ListPolicyFamiliesRequest{}) { // if err != nil { // return err // } @@ -226,16 +230,13 @@ func (c *internalClient) ListPolicyFamilies(ctx context.Context, req *ListPolicy // // Callers who need custom pagination logic should use // ListPolicyFamilies directly. -func (c *internalClient) ListPolicyFamiliesIter(ctx context.Context, req *ListPolicyFamiliesRequest, opts ...call.Option) iter.Seq2[*PolicyFamily, error] { +func (c *internalClient) ListPolicyFamiliesIter(ctx context.Context, req ListPolicyFamiliesRequest, opts ...call.Option) iter.Seq2[*PolicyFamily, error] { return func(yield func(*PolicyFamily, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListPolicyFamiliesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListPolicyFamilies(ctx, &pageReq, opts...) + resp, err := c.ListPolicyFamilies(ctx, pageReq, opts...) if err != nil { yield(nil, err) return diff --git a/policyfamilies/v2/genhelper.go b/policyfamilies/v2/genhelper.go old mode 100755 new mode 100644 index 3f90050..886d1e1 --- a/policyfamilies/v2/genhelper.go +++ b/policyfamilies/v2/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/policyfamilies/v2/wire.go b/policyfamilies/v2/wire.go old mode 100755 new mode 100644 index 238bf84..abbcb65 --- a/policyfamilies/v2/wire.go +++ b/policyfamilies/v2/wire.go @@ -3,35 +3,89 @@ package policyfamilies import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type getPolicyFamilyRequestWire struct { - PolicyFamilyId *string `json:"policy_family_id,omitempty"` - Version *int64 `json:"version,omitempty"` + PolicyFamilyId *string `json:"policy_family_id,omitempty"` + Version *wireInt64 `json:"version,omitempty"` } func getPolicyFamilyRequestToWire(v *GetPolicyFamilyRequest) (*getPolicyFamilyRequestWire, error) { if v == nil { return nil, nil } + versionWireValue, err := int64ToWire(v.Version) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetPolicyFamilyRequest.Version", err) + } return &getPolicyFamilyRequestWire{ PolicyFamilyId: v.PolicyFamilyId, - Version: v.Version, + Version: versionWireValue, }, nil } type listPolicyFamiliesRequestWire struct { - MaxResults *int64 `json:"max_results,omitempty"` - PageToken *string `json:"page_token,omitempty"` + MaxResults *wireInt64 `json:"max_results,omitempty"` + PageToken *string `json:"page_token,omitempty"` } func listPolicyFamiliesRequestToWire(v *ListPolicyFamiliesRequest) (*listPolicyFamiliesRequestWire, error) { if v == nil { return nil, nil } + maxResultsWireValue, err := int64ToWire(v.MaxResults) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListPolicyFamiliesRequest.MaxResults", err) + } return &listPolicyFamiliesRequestWire{ - MaxResults: v.MaxResults, + MaxResults: maxResultsWireValue, PageToken: v.PageToken, }, nil } diff --git a/postgres/CHANGELOG.md b/postgres/CHANGELOG.md index 6224c04..19f237c 100644 --- a/postgres/CHANGELOG.md +++ b/postgres/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/postgres/go.mod b/postgres/go.mod index 56beb6e..6674dde 100644 --- a/postgres/go.mod +++ b/postgres/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/postgres/internal/version.go b/postgres/internal/version.go index f225935..b6f0f09 100644 --- a/postgres/internal/version.go +++ b/postgres/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-postgres" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/postgres/v1/client.go b/postgres/v1/client.go old mode 100755 new mode 100644 index 9cac693..f8e604f --- a/postgres/v1/client.go +++ b/postgres/v1/client.go @@ -77,8 +77,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Creates a new database branch in the project. -func (c *internalClient) createBranchBase(ctx context.Context, req *CreateBranchRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := createBranchRequestToWire(req) +func (c *internalClient) createBranchBase(ctx context.Context, req CreateBranchRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := createBranchRequestToWire(&req) if err != nil { return nil, err } @@ -99,7 +99,11 @@ func (c *internalClient) createBranchBase(ctx context.Context, req *CreateBranch } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/branches") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -153,7 +157,7 @@ func (c *internalClient) createBranchBase(ctx context.Context, req *CreateBranch } // Creates a new database branch in the project. -func (c *internalClient) CreateBranch(ctx context.Context, req *CreateBranchRequest, opts ...call.Option) (*CreateBranchOperation, error) { +func (c *internalClient) CreateBranch(ctx context.Context, req CreateBranchRequest, opts ...call.Option) (*CreateBranchOperation, error) { operation, err := c.createBranchBase(ctx, req, opts...) if err != nil { return nil, err @@ -170,7 +174,7 @@ func (c *internalClient) CreateBranch(ctx context.Context, req *CreateBranchRequ // CreateBranchOperation tracks the state of the long-running operation started by CreateBranch. type CreateBranchOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -196,7 +200,7 @@ func (o *CreateBranchOperation) Metadata() (*BranchOperationMetadata, error) { // Done refreshes the operation and reports whether it has completed. func (o *CreateBranchOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -214,7 +218,7 @@ func (o *CreateBranchOperation) Done(ctx context.Context, opts ...call.Option) ( func (o *CreateBranchOperation) Wait(ctx context.Context, opts ...lro.Option) (*Branch, error) { var result *Branch poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -252,8 +256,8 @@ func (o *CreateBranchOperation) Wait(ctx context.Context, opts ...lro.Option) (* } // Register a Postgres database in the Unity Catalog. -func (c *internalClient) createCatalogBase(ctx context.Context, req *CreateCatalogRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := createCatalogRequestToWire(req) +func (c *internalClient) createCatalogBase(ctx context.Context, req CreateCatalogRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := createCatalogRequestToWire(&req) if err != nil { return nil, err } @@ -321,7 +325,7 @@ func (c *internalClient) createCatalogBase(ctx context.Context, req *CreateCatal } // Register a Postgres database in the Unity Catalog. -func (c *internalClient) CreateCatalog(ctx context.Context, req *CreateCatalogRequest, opts ...call.Option) (*CreateCatalogOperation, error) { +func (c *internalClient) CreateCatalog(ctx context.Context, req CreateCatalogRequest, opts ...call.Option) (*CreateCatalogOperation, error) { operation, err := c.createCatalogBase(ctx, req, opts...) if err != nil { return nil, err @@ -338,7 +342,7 @@ func (c *internalClient) CreateCatalog(ctx context.Context, req *CreateCatalogRe // CreateCatalogOperation tracks the state of the long-running operation started by CreateCatalog. type CreateCatalogOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -364,7 +368,7 @@ func (o *CreateCatalogOperation) Metadata() (*CatalogOperationMetadata, error) { // Done refreshes the operation and reports whether it has completed. func (o *CreateCatalogOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -382,7 +386,7 @@ func (o *CreateCatalogOperation) Done(ctx context.Context, opts ...call.Option) func (o *CreateCatalogOperation) Wait(ctx context.Context, opts ...lro.Option) (*Catalog, error) { var result *Catalog poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -423,8 +427,8 @@ func (o *CreateCatalogOperation) Wait(ctx context.Context, opts ...lro.Option) ( // tables in a Postgres schema as open-format Delta tables in Unity Catalog. // Once created, each table's change history is continuously written to its // corresponding Lakehouse table. -func (c *internalClient) createCdfConfigBase(ctx context.Context, req *CreateCdfConfigRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := createCdfConfigRequestToWire(req) +func (c *internalClient) createCdfConfigBase(ctx context.Context, req CreateCdfConfigRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := createCdfConfigRequestToWire(&req) if err != nil { return nil, err } @@ -445,7 +449,11 @@ func (c *internalClient) createCdfConfigBase(ctx context.Context, req *CreateCdf } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/cdf-configs") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -499,7 +507,7 @@ func (c *internalClient) createCdfConfigBase(ctx context.Context, req *CreateCdf // tables in a Postgres schema as open-format Delta tables in Unity Catalog. // Once created, each table's change history is continuously written to its // corresponding Lakehouse table. -func (c *internalClient) CreateCdfConfig(ctx context.Context, req *CreateCdfConfigRequest, opts ...call.Option) (*CreateCdfConfigOperation, error) { +func (c *internalClient) CreateCdfConfig(ctx context.Context, req CreateCdfConfigRequest, opts ...call.Option) (*CreateCdfConfigOperation, error) { operation, err := c.createCdfConfigBase(ctx, req, opts...) if err != nil { return nil, err @@ -516,7 +524,7 @@ func (c *internalClient) CreateCdfConfig(ctx context.Context, req *CreateCdfConf // CreateCdfConfigOperation tracks the state of the long-running operation started by CreateCdfConfig. type CreateCdfConfigOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -542,7 +550,7 @@ func (o *CreateCdfConfigOperation) Metadata() (*CdfConfigOperationMetadata, erro // Done refreshes the operation and reports whether it has completed. func (o *CreateCdfConfigOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -560,7 +568,7 @@ func (o *CreateCdfConfigOperation) Done(ctx context.Context, opts ...call.Option func (o *CreateCdfConfigOperation) Wait(ctx context.Context, opts ...lro.Option) (*CdfConfig, error) { var result *CdfConfig poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -598,8 +606,8 @@ func (o *CreateCdfConfigOperation) Wait(ctx context.Context, opts ...lro.Option) } // Enable Data API for a database. -func (c *internalClient) createDataApiBase(ctx context.Context, req *CreateDataApiRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := createDataApiRequestToWire(req) +func (c *internalClient) createDataApiBase(ctx context.Context, req CreateDataApiRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := createDataApiRequestToWire(&req) if err != nil { return nil, err } @@ -620,7 +628,11 @@ func (c *internalClient) createDataApiBase(ctx context.Context, req *CreateDataA } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/data-api") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -668,7 +680,7 @@ func (c *internalClient) createDataApiBase(ctx context.Context, req *CreateDataA } // Enable Data API for a database. -func (c *internalClient) CreateDataApi(ctx context.Context, req *CreateDataApiRequest, opts ...call.Option) (*CreateDataApiOperation, error) { +func (c *internalClient) CreateDataApi(ctx context.Context, req CreateDataApiRequest, opts ...call.Option) (*CreateDataApiOperation, error) { operation, err := c.createDataApiBase(ctx, req, opts...) if err != nil { return nil, err @@ -685,7 +697,7 @@ func (c *internalClient) CreateDataApi(ctx context.Context, req *CreateDataApiRe // CreateDataApiOperation tracks the state of the long-running operation started by CreateDataApi. type CreateDataApiOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -711,7 +723,7 @@ func (o *CreateDataApiOperation) Metadata() (*DataApiOperationMetadata, error) { // Done refreshes the operation and reports whether it has completed. func (o *CreateDataApiOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -729,7 +741,7 @@ func (o *CreateDataApiOperation) Done(ctx context.Context, opts ...call.Option) func (o *CreateDataApiOperation) Wait(ctx context.Context, opts ...lro.Option) (*DataApi, error) { var result *DataApi poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -770,8 +782,8 @@ func (o *CreateDataApiOperation) Wait(ctx context.Context, opts ...lro.Option) ( // // Creates a database in the specified branch. A branch can have multiple // databases. -func (c *internalClient) createDatabaseBase(ctx context.Context, req *CreateDatabaseRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := createDatabaseRequestToWire(req) +func (c *internalClient) createDatabaseBase(ctx context.Context, req CreateDatabaseRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := createDatabaseRequestToWire(&req) if err != nil { return nil, err } @@ -792,7 +804,11 @@ func (c *internalClient) createDatabaseBase(ctx context.Context, req *CreateData } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/databases") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -849,7 +865,7 @@ func (c *internalClient) createDatabaseBase(ctx context.Context, req *CreateData // // Creates a database in the specified branch. A branch can have multiple // databases. -func (c *internalClient) CreateDatabase(ctx context.Context, req *CreateDatabaseRequest, opts ...call.Option) (*CreateDatabaseOperation, error) { +func (c *internalClient) CreateDatabase(ctx context.Context, req CreateDatabaseRequest, opts ...call.Option) (*CreateDatabaseOperation, error) { operation, err := c.createDatabaseBase(ctx, req, opts...) if err != nil { return nil, err @@ -866,7 +882,7 @@ func (c *internalClient) CreateDatabase(ctx context.Context, req *CreateDatabase // CreateDatabaseOperation tracks the state of the long-running operation started by CreateDatabase. type CreateDatabaseOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -892,7 +908,7 @@ func (o *CreateDatabaseOperation) Metadata() (*DatabaseOperationMetadata, error) // Done refreshes the operation and reports whether it has completed. func (o *CreateDatabaseOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -910,7 +926,7 @@ func (o *CreateDatabaseOperation) Done(ctx context.Context, opts ...call.Option) func (o *CreateDatabaseOperation) Wait(ctx context.Context, opts ...lro.Option) (*Database, error) { var result *Database poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -948,8 +964,8 @@ func (o *CreateDatabaseOperation) Wait(ctx context.Context, opts ...lro.Option) } // Creates a new compute endpoint in the branch. -func (c *internalClient) createEndpointBase(ctx context.Context, req *CreateEndpointRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := createEndpointRequestToWire(req) +func (c *internalClient) createEndpointBase(ctx context.Context, req CreateEndpointRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := createEndpointRequestToWire(&req) if err != nil { return nil, err } @@ -970,7 +986,11 @@ func (c *internalClient) createEndpointBase(ctx context.Context, req *CreateEndp } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/endpoints") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1024,7 +1044,7 @@ func (c *internalClient) createEndpointBase(ctx context.Context, req *CreateEndp } // Creates a new compute endpoint in the branch. -func (c *internalClient) CreateEndpoint(ctx context.Context, req *CreateEndpointRequest, opts ...call.Option) (*CreateEndpointOperation, error) { +func (c *internalClient) CreateEndpoint(ctx context.Context, req CreateEndpointRequest, opts ...call.Option) (*CreateEndpointOperation, error) { operation, err := c.createEndpointBase(ctx, req, opts...) if err != nil { return nil, err @@ -1041,7 +1061,7 @@ func (c *internalClient) CreateEndpoint(ctx context.Context, req *CreateEndpoint // CreateEndpointOperation tracks the state of the long-running operation started by CreateEndpoint. type CreateEndpointOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -1067,7 +1087,7 @@ func (o *CreateEndpointOperation) Metadata() (*EndpointOperationMetadata, error) // Done refreshes the operation and reports whether it has completed. func (o *CreateEndpointOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -1085,7 +1105,7 @@ func (o *CreateEndpointOperation) Done(ctx context.Context, opts ...call.Option) func (o *CreateEndpointOperation) Wait(ctx context.Context, opts ...lro.Option) (*Endpoint, error) { var result *Endpoint poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -1124,8 +1144,8 @@ func (o *CreateEndpointOperation) Wait(ctx context.Context, opts ...lro.Option) // Creates a new Lakebase Autoscaling Postgres database project, which contains // branches and compute endpoints. -func (c *internalClient) createProjectBase(ctx context.Context, req *CreateProjectRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := createProjectRequestToWire(req) +func (c *internalClient) createProjectBase(ctx context.Context, req CreateProjectRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := createProjectRequestToWire(&req) if err != nil { return nil, err } @@ -1194,7 +1214,7 @@ func (c *internalClient) createProjectBase(ctx context.Context, req *CreateProje // Creates a new Lakebase Autoscaling Postgres database project, which contains // branches and compute endpoints. -func (c *internalClient) CreateProject(ctx context.Context, req *CreateProjectRequest, opts ...call.Option) (*CreateProjectOperation, error) { +func (c *internalClient) CreateProject(ctx context.Context, req CreateProjectRequest, opts ...call.Option) (*CreateProjectOperation, error) { operation, err := c.createProjectBase(ctx, req, opts...) if err != nil { return nil, err @@ -1211,7 +1231,7 @@ func (c *internalClient) CreateProject(ctx context.Context, req *CreateProjectRe // CreateProjectOperation tracks the state of the long-running operation started by CreateProject. type CreateProjectOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -1237,7 +1257,7 @@ func (o *CreateProjectOperation) Metadata() (*ProjectOperationMetadata, error) { // Done refreshes the operation and reports whether it has completed. func (o *CreateProjectOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -1255,7 +1275,7 @@ func (o *CreateProjectOperation) Done(ctx context.Context, opts ...call.Option) func (o *CreateProjectOperation) Wait(ctx context.Context, opts ...lro.Option) (*Project, error) { var result *Project poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -1293,8 +1313,8 @@ func (o *CreateProjectOperation) Wait(ctx context.Context, opts ...lro.Option) ( } // Creates a new Postgres role in the branch. -func (c *internalClient) createRoleBase(ctx context.Context, req *CreateRoleRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := createRoleRequestToWire(req) +func (c *internalClient) createRoleBase(ctx context.Context, req CreateRoleRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := createRoleRequestToWire(&req) if err != nil { return nil, err } @@ -1315,7 +1335,11 @@ func (c *internalClient) createRoleBase(ctx context.Context, req *CreateRoleRequ } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/roles") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1369,7 +1393,7 @@ func (c *internalClient) createRoleBase(ctx context.Context, req *CreateRoleRequ } // Creates a new Postgres role in the branch. -func (c *internalClient) CreateRole(ctx context.Context, req *CreateRoleRequest, opts ...call.Option) (*CreateRoleOperation, error) { +func (c *internalClient) CreateRole(ctx context.Context, req CreateRoleRequest, opts ...call.Option) (*CreateRoleOperation, error) { operation, err := c.createRoleBase(ctx, req, opts...) if err != nil { return nil, err @@ -1386,7 +1410,7 @@ func (c *internalClient) CreateRole(ctx context.Context, req *CreateRoleRequest, // CreateRoleOperation tracks the state of the long-running operation started by CreateRole. type CreateRoleOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -1412,7 +1436,7 @@ func (o *CreateRoleOperation) Metadata() (*RoleOperationMetadata, error) { // Done refreshes the operation and reports whether it has completed. func (o *CreateRoleOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -1430,7 +1454,7 @@ func (o *CreateRoleOperation) Done(ctx context.Context, opts ...call.Option) (bo func (o *CreateRoleOperation) Wait(ctx context.Context, opts ...lro.Option) (*Role, error) { var result *Role poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -1467,9 +1491,187 @@ func (o *CreateRoleOperation) Wait(ctx context.Context, opts ...lro.Option) (*Ro return result, nil } +// Creates a snapshot, an immutable point-in-time copy of a branch's data, +// within the project. +func (c *internalClient) createSnapshotBase(ctx context.Context, req CreateSnapshotRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := createSnapshotRequestToWire(&req) + if err != nil { + return nil, err + } + body, err := json.Marshal(wireReq.Snapshot) + if err != nil { + return nil, err + } + + headers := http.Header{} + headers.Set("Content-Type", "application/json") + if c.workspaceID != "" { + headers.Set("X-Databricks-Workspace-Id", c.workspaceID) + } + + baseURL, err := url.Parse(c.host) + if err != nil { + return nil, err + } + pb := pathBuilder{} + pb.literal("/api/2.0/postgres/") + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } + pb.literal("/snapshots") + baseURL.Path, baseURL.RawPath = pb.build() + queryParams := url.Values{} + if err := addQueryValue(queryParams, "snapshot_id", wireReq.SnapshotId); err != nil { + return nil, err + } + baseURL.RawQuery = queryParams.Encode() + urlStr := baseURL.String() + + var resp *Operation + + call := func(ctx context.Context) error { + httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ + Method: "POST", + URL: urlStr, + Credentials: c.credentials, + UserAgent: c.userAgent, + Headers: headers, + Body: bytes.NewBuffer(body), + }) + if err != nil { + return err + } + + respBody, _, err := executeHTTPCall(httpCallOptions{ + req: httpReq, + client: c.httpClient, + logger: c.logger, + }) + if err != nil { + return err + } + var wireResp operationWire + if err := json.Unmarshal(respBody, &wireResp); err != nil { + return err + } + resp, err = operationFromWire(&wireResp) + if err != nil { + return err + } + return nil + } + + if err := executeCall(ctx, call, opts); err != nil { + return nil, err + } + return resp, nil +} + +// Creates a snapshot, an immutable point-in-time copy of a branch's data, +// within the project. +func (c *internalClient) CreateSnapshot(ctx context.Context, req CreateSnapshotRequest, opts ...call.Option) (*CreateSnapshotOperation, error) { + operation, err := c.createSnapshotBase(ctx, req, opts...) + if err != nil { + return nil, err + } + if err := validateOperationName(operation.Name); err != nil { + return nil, err + } + return &CreateSnapshotOperation{ + operation: operation, + getOperation: c.getOperation, + }, nil +} + +// CreateSnapshotOperation tracks the state of the long-running operation started by CreateSnapshot. +type CreateSnapshotOperation struct { + operation *Operation + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) +} + +// Name returns the server-assigned operation name. +func (o *CreateSnapshotOperation) Name() *string { + return o.operation.Name +} + +// Metadata returns metadata associated with the operation. +func (o *CreateSnapshotOperation) Metadata() (*SnapshotOperationMetadata, error) { + if len(o.operation.Metadata) == 0 || bytes.Equal(bytes.TrimSpace(o.operation.Metadata), []byte("null")) { + return nil, nil + } + var metadata snapshotOperationMetadataWire + if err := json.Unmarshal(o.operation.Metadata, &metadata); err != nil { + return nil, fmt.Errorf("decode operation metadata: %w", err) + } + converted, err := snapshotOperationMetadataFromWire(&metadata) + if err != nil { + return nil, err + } + return converted, nil +} + +// Done refreshes the operation and reports whether it has completed. +func (o *CreateSnapshotOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) + if err != nil { + return false, err + } + if err := validateOperationName(operation.Name); err != nil { + return false, err + } + o.operation = operation + if operation.Done == nil { + return false, fmt.Errorf("invalid operation response: missing done field") + } + return *operation.Done, nil +} + +// Wait polls the operation until it completes. +func (o *CreateSnapshotOperation) Wait(ctx context.Context, opts ...lro.Option) (*Snapshot, error) { + var result *Snapshot + poll := func(ctx context.Context) error { + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) + if err != nil { + return err + } + if err := validateOperationName(operation.Name); err != nil { + return err + } + o.operation = operation + if operation.Done == nil { + return fmt.Errorf("invalid operation response: missing done field") + } + if !*operation.Done { + return errOperationStillRunning + } + if operationError, ok := operation.Result.(*Operation_Result_Error); ok && operationError != nil { + return fmt.Errorf("operation failed: %w", &operationError.Error) + } + operationResponse, ok := operation.Result.(*Operation_Result_Response) + if !ok || operationResponse == nil || len(operationResponse.Response) == 0 || bytes.Equal(bytes.TrimSpace(operationResponse.Response), []byte("null")) { + return fmt.Errorf("operation completed without a response") + } + var response snapshotWire + if err := json.Unmarshal(operationResponse.Response, &response); err != nil { + return fmt.Errorf("decode operation response: %w", err) + } + result, err = snapshotFromWire(&response) + if err != nil { + return err + } + return nil + } + if err := executeWait(ctx, poll, opts...); err != nil { + return nil, err + } + return result, nil +} + // Create a Synced Table. -func (c *internalClient) createSyncedTableBase(ctx context.Context, req *CreateSyncedTableRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := createSyncedTableRequestToWire(req) +func (c *internalClient) createSyncedTableBase(ctx context.Context, req CreateSyncedTableRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := createSyncedTableRequestToWire(&req) if err != nil { return nil, err } @@ -1537,7 +1739,7 @@ func (c *internalClient) createSyncedTableBase(ctx context.Context, req *CreateS } // Create a Synced Table. -func (c *internalClient) CreateSyncedTable(ctx context.Context, req *CreateSyncedTableRequest, opts ...call.Option) (*CreateSyncedTableOperation, error) { +func (c *internalClient) CreateSyncedTable(ctx context.Context, req CreateSyncedTableRequest, opts ...call.Option) (*CreateSyncedTableOperation, error) { operation, err := c.createSyncedTableBase(ctx, req, opts...) if err != nil { return nil, err @@ -1554,7 +1756,7 @@ func (c *internalClient) CreateSyncedTable(ctx context.Context, req *CreateSynce // CreateSyncedTableOperation tracks the state of the long-running operation started by CreateSyncedTable. type CreateSyncedTableOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -1580,7 +1782,7 @@ func (o *CreateSyncedTableOperation) Metadata() (*SyncedTableOperationMetadata, // Done refreshes the operation and reports whether it has completed. func (o *CreateSyncedTableOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -1598,7 +1800,7 @@ func (o *CreateSyncedTableOperation) Done(ctx context.Context, opts ...call.Opti func (o *CreateSyncedTableOperation) Wait(ctx context.Context, opts ...lro.Option) (*SyncedTable, error) { var result *SyncedTable poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -1636,8 +1838,8 @@ func (o *CreateSyncedTableOperation) Wait(ctx context.Context, opts ...lro.Optio } // Deletes the specified database branch. -func (c *internalClient) deleteBranchBase(ctx context.Context, req *DeleteBranchRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := deleteBranchRequestToWire(req) +func (c *internalClient) deleteBranchBase(ctx context.Context, req DeleteBranchRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := deleteBranchRequestToWire(&req) if err != nil { return nil, err } @@ -1654,7 +1856,11 @@ func (c *internalClient) deleteBranchBase(ctx context.Context, req *DeleteBranch } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "purge", wireReq.Purge); err != nil { @@ -1703,7 +1909,7 @@ func (c *internalClient) deleteBranchBase(ctx context.Context, req *DeleteBranch } // Deletes the specified database branch. -func (c *internalClient) DeleteBranch(ctx context.Context, req *DeleteBranchRequest, opts ...call.Option) (*DeleteBranchOperation, error) { +func (c *internalClient) DeleteBranch(ctx context.Context, req DeleteBranchRequest, opts ...call.Option) (*DeleteBranchOperation, error) { operation, err := c.deleteBranchBase(ctx, req, opts...) if err != nil { return nil, err @@ -1720,7 +1926,7 @@ func (c *internalClient) DeleteBranch(ctx context.Context, req *DeleteBranchRequ // DeleteBranchOperation tracks the state of the long-running operation started by DeleteBranch. type DeleteBranchOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -1746,7 +1952,7 @@ func (o *DeleteBranchOperation) Metadata() (*BranchOperationMetadata, error) { // Done refreshes the operation and reports whether it has completed. func (o *DeleteBranchOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -1763,7 +1969,7 @@ func (o *DeleteBranchOperation) Done(ctx context.Context, opts ...call.Option) ( // Wait polls the operation until it completes. func (o *DeleteBranchOperation) Wait(ctx context.Context, opts ...lro.Option) error { poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -1793,7 +1999,7 @@ func (o *DeleteBranchOperation) Wait(ctx context.Context, opts ...lro.Option) er } // Delete a Database Catalog. -func (c *internalClient) deleteCatalogBase(ctx context.Context, req *DeleteCatalogRequest, opts ...call.Option) (*Operation, error) { +func (c *internalClient) deleteCatalogBase(ctx context.Context, req DeleteCatalogRequest, opts ...call.Option) (*Operation, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1807,7 +2013,11 @@ func (c *internalClient) deleteCatalogBase(ctx context.Context, req *DeleteCatal } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1853,7 +2063,7 @@ func (c *internalClient) deleteCatalogBase(ctx context.Context, req *DeleteCatal } // Delete a Database Catalog. -func (c *internalClient) DeleteCatalog(ctx context.Context, req *DeleteCatalogRequest, opts ...call.Option) (*DeleteCatalogOperation, error) { +func (c *internalClient) DeleteCatalog(ctx context.Context, req DeleteCatalogRequest, opts ...call.Option) (*DeleteCatalogOperation, error) { operation, err := c.deleteCatalogBase(ctx, req, opts...) if err != nil { return nil, err @@ -1870,7 +2080,7 @@ func (c *internalClient) DeleteCatalog(ctx context.Context, req *DeleteCatalogRe // DeleteCatalogOperation tracks the state of the long-running operation started by DeleteCatalog. type DeleteCatalogOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -1896,7 +2106,7 @@ func (o *DeleteCatalogOperation) Metadata() (*CatalogOperationMetadata, error) { // Done refreshes the operation and reports whether it has completed. func (o *DeleteCatalogOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -1913,7 +2123,7 @@ func (o *DeleteCatalogOperation) Done(ctx context.Context, opts ...call.Option) // Wait polls the operation until it completes. func (o *DeleteCatalogOperation) Wait(ctx context.Context, opts ...lro.Option) error { poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -1945,8 +2155,8 @@ func (o *DeleteCatalogOperation) Wait(ctx context.Context, opts ...lro.Option) e // Delete a CDF configuration and stop materializing the change data feed. When // force=true, also drops the Delta tables in Unity Catalog. When force=false // (default), the existing tables are preserved at their last state. -func (c *internalClient) deleteCdfConfigBase(ctx context.Context, req *DeleteCdfConfigRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := deleteCdfConfigRequestToWire(req) +func (c *internalClient) deleteCdfConfigBase(ctx context.Context, req DeleteCdfConfigRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := deleteCdfConfigRequestToWire(&req) if err != nil { return nil, err } @@ -1963,7 +2173,11 @@ func (c *internalClient) deleteCdfConfigBase(ctx context.Context, req *DeleteCdf } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "force", wireReq.Force); err != nil { @@ -2014,7 +2228,7 @@ func (c *internalClient) deleteCdfConfigBase(ctx context.Context, req *DeleteCdf // Delete a CDF configuration and stop materializing the change data feed. When // force=true, also drops the Delta tables in Unity Catalog. When force=false // (default), the existing tables are preserved at their last state. -func (c *internalClient) DeleteCdfConfig(ctx context.Context, req *DeleteCdfConfigRequest, opts ...call.Option) (*DeleteCdfConfigOperation, error) { +func (c *internalClient) DeleteCdfConfig(ctx context.Context, req DeleteCdfConfigRequest, opts ...call.Option) (*DeleteCdfConfigOperation, error) { operation, err := c.deleteCdfConfigBase(ctx, req, opts...) if err != nil { return nil, err @@ -2031,7 +2245,7 @@ func (c *internalClient) DeleteCdfConfig(ctx context.Context, req *DeleteCdfConf // DeleteCdfConfigOperation tracks the state of the long-running operation started by DeleteCdfConfig. type DeleteCdfConfigOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -2057,7 +2271,7 @@ func (o *DeleteCdfConfigOperation) Metadata() (*CdfConfigOperationMetadata, erro // Done refreshes the operation and reports whether it has completed. func (o *DeleteCdfConfigOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -2074,7 +2288,7 @@ func (o *DeleteCdfConfigOperation) Done(ctx context.Context, opts ...call.Option // Wait polls the operation until it completes. func (o *DeleteCdfConfigOperation) Wait(ctx context.Context, opts ...lro.Option) error { poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -2104,7 +2318,7 @@ func (o *DeleteCdfConfigOperation) Wait(ctx context.Context, opts ...lro.Option) } // Disable Data API for a database. -func (c *internalClient) deleteDataApiBase(ctx context.Context, req *DeleteDataApiRequest, opts ...call.Option) (*Operation, error) { +func (c *internalClient) deleteDataApiBase(ctx context.Context, req DeleteDataApiRequest, opts ...call.Option) (*Operation, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2118,7 +2332,11 @@ func (c *internalClient) deleteDataApiBase(ctx context.Context, req *DeleteDataA } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2164,7 +2382,7 @@ func (c *internalClient) deleteDataApiBase(ctx context.Context, req *DeleteDataA } // Disable Data API for a database. -func (c *internalClient) DeleteDataApi(ctx context.Context, req *DeleteDataApiRequest, opts ...call.Option) (*DeleteDataApiOperation, error) { +func (c *internalClient) DeleteDataApi(ctx context.Context, req DeleteDataApiRequest, opts ...call.Option) (*DeleteDataApiOperation, error) { operation, err := c.deleteDataApiBase(ctx, req, opts...) if err != nil { return nil, err @@ -2181,7 +2399,7 @@ func (c *internalClient) DeleteDataApi(ctx context.Context, req *DeleteDataApiRe // DeleteDataApiOperation tracks the state of the long-running operation started by DeleteDataApi. type DeleteDataApiOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -2207,7 +2425,7 @@ func (o *DeleteDataApiOperation) Metadata() (*DataApiOperationMetadata, error) { // Done refreshes the operation and reports whether it has completed. func (o *DeleteDataApiOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -2224,7 +2442,7 @@ func (o *DeleteDataApiOperation) Done(ctx context.Context, opts ...call.Option) // Wait polls the operation until it completes. func (o *DeleteDataApiOperation) Wait(ctx context.Context, opts ...lro.Option) error { poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -2254,7 +2472,7 @@ func (o *DeleteDataApiOperation) Wait(ctx context.Context, opts ...lro.Option) e } // Delete a Database. -func (c *internalClient) deleteDatabaseBase(ctx context.Context, req *DeleteDatabaseRequest, opts ...call.Option) (*Operation, error) { +func (c *internalClient) deleteDatabaseBase(ctx context.Context, req DeleteDatabaseRequest, opts ...call.Option) (*Operation, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2268,7 +2486,11 @@ func (c *internalClient) deleteDatabaseBase(ctx context.Context, req *DeleteData } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2314,7 +2536,7 @@ func (c *internalClient) deleteDatabaseBase(ctx context.Context, req *DeleteData } // Delete a Database. -func (c *internalClient) DeleteDatabase(ctx context.Context, req *DeleteDatabaseRequest, opts ...call.Option) (*DeleteDatabaseOperation, error) { +func (c *internalClient) DeleteDatabase(ctx context.Context, req DeleteDatabaseRequest, opts ...call.Option) (*DeleteDatabaseOperation, error) { operation, err := c.deleteDatabaseBase(ctx, req, opts...) if err != nil { return nil, err @@ -2331,7 +2553,7 @@ func (c *internalClient) DeleteDatabase(ctx context.Context, req *DeleteDatabase // DeleteDatabaseOperation tracks the state of the long-running operation started by DeleteDatabase. type DeleteDatabaseOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -2357,7 +2579,7 @@ func (o *DeleteDatabaseOperation) Metadata() (*DatabaseOperationMetadata, error) // Done refreshes the operation and reports whether it has completed. func (o *DeleteDatabaseOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -2374,7 +2596,7 @@ func (o *DeleteDatabaseOperation) Done(ctx context.Context, opts ...call.Option) // Wait polls the operation until it completes. func (o *DeleteDatabaseOperation) Wait(ctx context.Context, opts ...lro.Option) error { poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -2404,7 +2626,7 @@ func (o *DeleteDatabaseOperation) Wait(ctx context.Context, opts ...lro.Option) } // Deletes the specified compute endpoint. -func (c *internalClient) deleteEndpointBase(ctx context.Context, req *DeleteEndpointRequest, opts ...call.Option) (*Operation, error) { +func (c *internalClient) deleteEndpointBase(ctx context.Context, req DeleteEndpointRequest, opts ...call.Option) (*Operation, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2418,7 +2640,11 @@ func (c *internalClient) deleteEndpointBase(ctx context.Context, req *DeleteEndp } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2464,7 +2690,7 @@ func (c *internalClient) deleteEndpointBase(ctx context.Context, req *DeleteEndp } // Deletes the specified compute endpoint. -func (c *internalClient) DeleteEndpoint(ctx context.Context, req *DeleteEndpointRequest, opts ...call.Option) (*DeleteEndpointOperation, error) { +func (c *internalClient) DeleteEndpoint(ctx context.Context, req DeleteEndpointRequest, opts ...call.Option) (*DeleteEndpointOperation, error) { operation, err := c.deleteEndpointBase(ctx, req, opts...) if err != nil { return nil, err @@ -2481,7 +2707,7 @@ func (c *internalClient) DeleteEndpoint(ctx context.Context, req *DeleteEndpoint // DeleteEndpointOperation tracks the state of the long-running operation started by DeleteEndpoint. type DeleteEndpointOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -2507,7 +2733,7 @@ func (o *DeleteEndpointOperation) Metadata() (*EndpointOperationMetadata, error) // Done refreshes the operation and reports whether it has completed. func (o *DeleteEndpointOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -2524,7 +2750,7 @@ func (o *DeleteEndpointOperation) Done(ctx context.Context, opts ...call.Option) // Wait polls the operation until it completes. func (o *DeleteEndpointOperation) Wait(ctx context.Context, opts ...lro.Option) error { poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -2554,8 +2780,8 @@ func (o *DeleteEndpointOperation) Wait(ctx context.Context, opts ...lro.Option) } // Deletes the specified database project. -func (c *internalClient) deleteProjectBase(ctx context.Context, req *DeleteProjectRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := deleteProjectRequestToWire(req) +func (c *internalClient) deleteProjectBase(ctx context.Context, req DeleteProjectRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := deleteProjectRequestToWire(&req) if err != nil { return nil, err } @@ -2572,7 +2798,11 @@ func (c *internalClient) deleteProjectBase(ctx context.Context, req *DeleteProje } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "purge", wireReq.Purge); err != nil { @@ -2621,7 +2851,7 @@ func (c *internalClient) deleteProjectBase(ctx context.Context, req *DeleteProje } // Deletes the specified database project. -func (c *internalClient) DeleteProject(ctx context.Context, req *DeleteProjectRequest, opts ...call.Option) (*DeleteProjectOperation, error) { +func (c *internalClient) DeleteProject(ctx context.Context, req DeleteProjectRequest, opts ...call.Option) (*DeleteProjectOperation, error) { operation, err := c.deleteProjectBase(ctx, req, opts...) if err != nil { return nil, err @@ -2638,7 +2868,7 @@ func (c *internalClient) DeleteProject(ctx context.Context, req *DeleteProjectRe // DeleteProjectOperation tracks the state of the long-running operation started by DeleteProject. type DeleteProjectOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -2664,7 +2894,7 @@ func (o *DeleteProjectOperation) Metadata() (*ProjectOperationMetadata, error) { // Done refreshes the operation and reports whether it has completed. func (o *DeleteProjectOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -2681,7 +2911,7 @@ func (o *DeleteProjectOperation) Done(ctx context.Context, opts ...call.Option) // Wait polls the operation until it completes. func (o *DeleteProjectOperation) Wait(ctx context.Context, opts ...lro.Option) error { poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -2711,8 +2941,8 @@ func (o *DeleteProjectOperation) Wait(ctx context.Context, opts ...lro.Option) e } // Deletes the specified Postgres role. -func (c *internalClient) deleteRoleBase(ctx context.Context, req *DeleteRoleRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := deleteRoleRequestToWire(req) +func (c *internalClient) deleteRoleBase(ctx context.Context, req DeleteRoleRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := deleteRoleRequestToWire(&req) if err != nil { return nil, err } @@ -2729,7 +2959,11 @@ func (c *internalClient) deleteRoleBase(ctx context.Context, req *DeleteRoleRequ } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "reassign_owned_to", wireReq.ReassignOwnedTo); err != nil { @@ -2778,7 +3012,7 @@ func (c *internalClient) deleteRoleBase(ctx context.Context, req *DeleteRoleRequ } // Deletes the specified Postgres role. -func (c *internalClient) DeleteRole(ctx context.Context, req *DeleteRoleRequest, opts ...call.Option) (*DeleteRoleOperation, error) { +func (c *internalClient) DeleteRole(ctx context.Context, req DeleteRoleRequest, opts ...call.Option) (*DeleteRoleOperation, error) { operation, err := c.deleteRoleBase(ctx, req, opts...) if err != nil { return nil, err @@ -2795,7 +3029,7 @@ func (c *internalClient) DeleteRole(ctx context.Context, req *DeleteRoleRequest, // DeleteRoleOperation tracks the state of the long-running operation started by DeleteRole. type DeleteRoleOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -2821,7 +3055,7 @@ func (o *DeleteRoleOperation) Metadata() (*RoleOperationMetadata, error) { // Done refreshes the operation and reports whether it has completed. func (o *DeleteRoleOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -2838,7 +3072,7 @@ func (o *DeleteRoleOperation) Done(ctx context.Context, opts ...call.Option) (bo // Wait polls the operation until it completes. func (o *DeleteRoleOperation) Wait(ctx context.Context, opts ...lro.Option) error { poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -2867,8 +3101,8 @@ func (o *DeleteRoleOperation) Wait(ctx context.Context, opts ...lro.Option) erro return nil } -// Delete a Synced Table. -func (c *internalClient) deleteSyncedTableBase(ctx context.Context, req *DeleteSyncedTableRequest, opts ...call.Option) (*Operation, error) { +// Deletes the specified snapshot. +func (c *internalClient) deleteSnapshotBase(ctx context.Context, req DeleteSnapshotRequest, opts ...call.Option) (*Operation, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2882,7 +3116,11 @@ func (c *internalClient) deleteSyncedTableBase(ctx context.Context, req *DeleteS } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2927,42 +3165,42 @@ func (c *internalClient) deleteSyncedTableBase(ctx context.Context, req *DeleteS return resp, nil } -// Delete a Synced Table. -func (c *internalClient) DeleteSyncedTable(ctx context.Context, req *DeleteSyncedTableRequest, opts ...call.Option) (*DeleteSyncedTableOperation, error) { - operation, err := c.deleteSyncedTableBase(ctx, req, opts...) +// Deletes the specified snapshot. +func (c *internalClient) DeleteSnapshot(ctx context.Context, req DeleteSnapshotRequest, opts ...call.Option) (*DeleteSnapshotOperation, error) { + operation, err := c.deleteSnapshotBase(ctx, req, opts...) if err != nil { return nil, err } if err := validateOperationName(operation.Name); err != nil { return nil, err } - return &DeleteSyncedTableOperation{ + return &DeleteSnapshotOperation{ operation: operation, getOperation: c.getOperation, }, nil } -// DeleteSyncedTableOperation tracks the state of the long-running operation started by DeleteSyncedTable. -type DeleteSyncedTableOperation struct { +// DeleteSnapshotOperation tracks the state of the long-running operation started by DeleteSnapshot. +type DeleteSnapshotOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. -func (o *DeleteSyncedTableOperation) Name() *string { +func (o *DeleteSnapshotOperation) Name() *string { return o.operation.Name } // Metadata returns metadata associated with the operation. -func (o *DeleteSyncedTableOperation) Metadata() (*SyncedTableOperationMetadata, error) { +func (o *DeleteSnapshotOperation) Metadata() (*SnapshotOperationMetadata, error) { if len(o.operation.Metadata) == 0 || bytes.Equal(bytes.TrimSpace(o.operation.Metadata), []byte("null")) { return nil, nil } - var metadata syncedTableOperationMetadataWire + var metadata snapshotOperationMetadataWire if err := json.Unmarshal(o.operation.Metadata, &metadata); err != nil { return nil, fmt.Errorf("decode operation metadata: %w", err) } - converted, err := syncedTableOperationMetadataFromWire(&metadata) + converted, err := snapshotOperationMetadataFromWire(&metadata) if err != nil { return nil, err } @@ -2970,8 +3208,8 @@ func (o *DeleteSyncedTableOperation) Metadata() (*SyncedTableOperationMetadata, } // Done refreshes the operation and reports whether it has completed. -func (o *DeleteSyncedTableOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) +func (o *DeleteSnapshotOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -2986,9 +3224,9 @@ func (o *DeleteSyncedTableOperation) Done(ctx context.Context, opts ...call.Opti } // Wait polls the operation until it completes. -func (o *DeleteSyncedTableOperation) Wait(ctx context.Context, opts ...lro.Option) error { +func (o *DeleteSnapshotOperation) Wait(ctx context.Context, opts ...lro.Option) error { poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -3017,16 +3255,8 @@ func (o *DeleteSyncedTableOperation) Wait(ctx context.Context, opts ...lro.Optio return nil } -// Generate OAuth credentials for a Postgres database. -func (c *internalClient) GenerateDatabaseCredential(ctx context.Context, req *GenerateDatabaseCredentialRequest, opts ...call.Option) (*DatabaseCredential, error) { - wireReq, err := generateDatabaseCredentialRequestToWire(req) - if err != nil { - return nil, err - } - body, err := json.Marshal(wireReq) - if err != nil { - return nil, err - } +// Delete a Synced Table. +func (c *internalClient) deleteSyncedTableBase(ctx context.Context, req DeleteSyncedTableRequest, opts ...call.Option) (*Operation, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -3038,21 +3268,27 @@ func (c *internalClient) GenerateDatabaseCredential(ctx context.Context, req *Ge if err != nil { return nil, err } - baseURL.Path = "/api/2.0/postgres/credentials" + pb := pathBuilder{} + pb.literal("/api/2.0/postgres/") + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } + baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() urlStr := baseURL.String() - var resp *DatabaseCredential + var resp *Operation call := func(ctx context.Context) error { httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ - Method: "POST", + Method: "DELETE", URL: urlStr, Credentials: c.credentials, UserAgent: c.userAgent, Headers: headers, - Body: bytes.NewBuffer(body), }) if err != nil { return err @@ -3066,11 +3302,11 @@ func (c *internalClient) GenerateDatabaseCredential(ctx context.Context, req *Ge if err != nil { return err } - var wireResp databaseCredentialWire + var wireResp operationWire if err := json.Unmarshal(respBody, &wireResp); err != nil { return err } - resp, err = databaseCredentialFromWire(&wireResp) + resp, err = operationFromWire(&wireResp) if err != nil { return err } @@ -3083,68 +3319,228 @@ func (c *internalClient) GenerateDatabaseCredential(ctx context.Context, req *Ge return resp, nil } -// Retrieves information about the specified database branch. -func (c *internalClient) GetBranch(ctx context.Context, req *GetBranchRequest, opts ...call.Option) (*Branch, error) { - - headers := http.Header{} - headers.Set("Content-Type", "application/json") - if c.workspaceID != "" { - headers.Set("X-Databricks-Workspace-Id", c.workspaceID) - } - - baseURL, err := url.Parse(c.host) +// Delete a Synced Table. +func (c *internalClient) DeleteSyncedTable(ctx context.Context, req DeleteSyncedTableRequest, opts ...call.Option) (*DeleteSyncedTableOperation, error) { + operation, err := c.deleteSyncedTableBase(ctx, req, opts...) if err != nil { return nil, err } - pb := pathBuilder{} - pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) - baseURL.Path, baseURL.RawPath = pb.build() - queryParams := url.Values{} - baseURL.RawQuery = queryParams.Encode() - urlStr := baseURL.String() - - var resp *Branch - - call := func(ctx context.Context) error { - httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ - Method: "GET", - URL: urlStr, - Credentials: c.credentials, - UserAgent: c.userAgent, - Headers: headers, - }) - if err != nil { - return err - } - - respBody, _, err := executeHTTPCall(httpCallOptions{ - req: httpReq, - client: c.httpClient, - logger: c.logger, - }) - if err != nil { - return err - } - var wireResp branchWire - if err := json.Unmarshal(respBody, &wireResp); err != nil { - return err - } - resp, err = branchFromWire(&wireResp) - if err != nil { - return err - } - return nil - } - - if err := executeCall(ctx, call, opts); err != nil { + if err := validateOperationName(operation.Name); err != nil { return nil, err } - return resp, nil + return &DeleteSyncedTableOperation{ + operation: operation, + getOperation: c.getOperation, + }, nil +} + +// DeleteSyncedTableOperation tracks the state of the long-running operation started by DeleteSyncedTable. +type DeleteSyncedTableOperation struct { + operation *Operation + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) +} + +// Name returns the server-assigned operation name. +func (o *DeleteSyncedTableOperation) Name() *string { + return o.operation.Name +} + +// Metadata returns metadata associated with the operation. +func (o *DeleteSyncedTableOperation) Metadata() (*SyncedTableOperationMetadata, error) { + if len(o.operation.Metadata) == 0 || bytes.Equal(bytes.TrimSpace(o.operation.Metadata), []byte("null")) { + return nil, nil + } + var metadata syncedTableOperationMetadataWire + if err := json.Unmarshal(o.operation.Metadata, &metadata); err != nil { + return nil, fmt.Errorf("decode operation metadata: %w", err) + } + converted, err := syncedTableOperationMetadataFromWire(&metadata) + if err != nil { + return nil, err + } + return converted, nil +} + +// Done refreshes the operation and reports whether it has completed. +func (o *DeleteSyncedTableOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) + if err != nil { + return false, err + } + if err := validateOperationName(operation.Name); err != nil { + return false, err + } + o.operation = operation + if operation.Done == nil { + return false, fmt.Errorf("invalid operation response: missing done field") + } + return *operation.Done, nil +} + +// Wait polls the operation until it completes. +func (o *DeleteSyncedTableOperation) Wait(ctx context.Context, opts ...lro.Option) error { + poll := func(ctx context.Context) error { + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) + if err != nil { + return err + } + if err := validateOperationName(operation.Name); err != nil { + return err + } + o.operation = operation + if operation.Done == nil { + return fmt.Errorf("invalid operation response: missing done field") + } + if !*operation.Done { + return errOperationStillRunning + } + if operationError, ok := operation.Result.(*Operation_Result_Error); ok && operationError != nil { + return fmt.Errorf("operation failed: %w", &operationError.Error) + } + operationResponse, ok := operation.Result.(*Operation_Result_Response) + if !ok || operationResponse == nil || len(operationResponse.Response) == 0 || bytes.Equal(bytes.TrimSpace(operationResponse.Response), []byte("null")) { + return fmt.Errorf("operation completed without a response") + } + return nil + } + if err := executeWait(ctx, poll, opts...); err != nil { + return err + } + return nil +} + +// Generate OAuth credentials for a Postgres database. +func (c *internalClient) GenerateDatabaseCredential(ctx context.Context, req GenerateDatabaseCredentialRequest, opts ...call.Option) (*DatabaseCredential, error) { + wireReq, err := generateDatabaseCredentialRequestToWire(&req) + if err != nil { + return nil, err + } + body, err := json.Marshal(wireReq) + if err != nil { + return nil, err + } + + headers := http.Header{} + headers.Set("Content-Type", "application/json") + if c.workspaceID != "" { + headers.Set("X-Databricks-Workspace-Id", c.workspaceID) + } + + baseURL, err := url.Parse(c.host) + if err != nil { + return nil, err + } + baseURL.Path = "/api/2.0/postgres/credentials" + queryParams := url.Values{} + baseURL.RawQuery = queryParams.Encode() + urlStr := baseURL.String() + + var resp *DatabaseCredential + + call := func(ctx context.Context) error { + httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ + Method: "POST", + URL: urlStr, + Credentials: c.credentials, + UserAgent: c.userAgent, + Headers: headers, + Body: bytes.NewBuffer(body), + }) + if err != nil { + return err + } + + respBody, _, err := executeHTTPCall(httpCallOptions{ + req: httpReq, + client: c.httpClient, + logger: c.logger, + }) + if err != nil { + return err + } + var wireResp databaseCredentialWire + if err := json.Unmarshal(respBody, &wireResp); err != nil { + return err + } + resp, err = databaseCredentialFromWire(&wireResp) + if err != nil { + return err + } + return nil + } + + if err := executeCall(ctx, call, opts); err != nil { + return nil, err + } + return resp, nil +} + +// Retrieves information about the specified database branch. +func (c *internalClient) GetBranch(ctx context.Context, req GetBranchRequest, opts ...call.Option) (*Branch, error) { + + headers := http.Header{} + headers.Set("Content-Type", "application/json") + if c.workspaceID != "" { + headers.Set("X-Databricks-Workspace-Id", c.workspaceID) + } + + baseURL, err := url.Parse(c.host) + if err != nil { + return nil, err + } + pb := pathBuilder{} + pb.literal("/api/2.0/postgres/") + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } + baseURL.Path, baseURL.RawPath = pb.build() + queryParams := url.Values{} + baseURL.RawQuery = queryParams.Encode() + urlStr := baseURL.String() + + var resp *Branch + + call := func(ctx context.Context) error { + httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ + Method: "GET", + URL: urlStr, + Credentials: c.credentials, + UserAgent: c.userAgent, + Headers: headers, + }) + if err != nil { + return err + } + + respBody, _, err := executeHTTPCall(httpCallOptions{ + req: httpReq, + client: c.httpClient, + logger: c.logger, + }) + if err != nil { + return err + } + var wireResp branchWire + if err := json.Unmarshal(respBody, &wireResp); err != nil { + return err + } + resp, err = branchFromWire(&wireResp) + if err != nil { + return err + } + return nil + } + + if err := executeCall(ctx, call, opts); err != nil { + return nil, err + } + return resp, nil } // Get a Database Catalog. -func (c *internalClient) GetCatalog(ctx context.Context, req *GetCatalogRequest, opts ...call.Option) (*Catalog, error) { +func (c *internalClient) GetCatalog(ctx context.Context, req GetCatalogRequest, opts ...call.Option) (*Catalog, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -3158,7 +3554,11 @@ func (c *internalClient) GetCatalog(ctx context.Context, req *GetCatalogRequest, } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -3206,7 +3606,7 @@ func (c *internalClient) GetCatalog(ctx context.Context, req *GetCatalogRequest, // Get a single Lakebase CDF configuration, including the source Postgres // schema, target Unity Catalog schema, and the identity under which writes are // authorized. -func (c *internalClient) GetCdfConfig(ctx context.Context, req *GetCdfConfigRequest, opts ...call.Option) (*CdfConfig, error) { +func (c *internalClient) GetCdfConfig(ctx context.Context, req GetCdfConfigRequest, opts ...call.Option) (*CdfConfig, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -3220,7 +3620,11 @@ func (c *internalClient) GetCdfConfig(ctx context.Context, req *GetCdfConfigRequ } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -3267,7 +3671,7 @@ func (c *internalClient) GetCdfConfig(ctx context.Context, req *GetCdfConfigRequ // Get the CDF status of a single table within a Lakebase CDF configuration, // including its current state and the last committed position in the feed. -func (c *internalClient) GetCdfStatus(ctx context.Context, req *GetCdfStatusRequest, opts ...call.Option) (*CdfStatus, error) { +func (c *internalClient) GetCdfStatus(ctx context.Context, req GetCdfStatusRequest, opts ...call.Option) (*CdfStatus, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -3281,7 +3685,11 @@ func (c *internalClient) GetCdfStatus(ctx context.Context, req *GetCdfStatusRequ } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -3327,7 +3735,7 @@ func (c *internalClient) GetCdfStatus(ctx context.Context, req *GetCdfStatusRequ } // Get Data API configuration for a database. -func (c *internalClient) GetDataApi(ctx context.Context, req *GetDataApiRequest, opts ...call.Option) (*DataApi, error) { +func (c *internalClient) GetDataApi(ctx context.Context, req GetDataApiRequest, opts ...call.Option) (*DataApi, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -3341,7 +3749,11 @@ func (c *internalClient) GetDataApi(ctx context.Context, req *GetDataApiRequest, } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -3387,7 +3799,7 @@ func (c *internalClient) GetDataApi(ctx context.Context, req *GetDataApiRequest, } // Get a Database. -func (c *internalClient) GetDatabase(ctx context.Context, req *GetDatabaseRequest, opts ...call.Option) (*Database, error) { +func (c *internalClient) GetDatabase(ctx context.Context, req GetDatabaseRequest, opts ...call.Option) (*Database, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -3401,7 +3813,11 @@ func (c *internalClient) GetDatabase(ctx context.Context, req *GetDatabaseReques } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -3448,7 +3864,7 @@ func (c *internalClient) GetDatabase(ctx context.Context, req *GetDatabaseReques // Retrieves information about the specified compute endpoint, including its // connection details and operational state. -func (c *internalClient) GetEndpoint(ctx context.Context, req *GetEndpointRequest, opts ...call.Option) (*Endpoint, error) { +func (c *internalClient) GetEndpoint(ctx context.Context, req GetEndpointRequest, opts ...call.Option) (*Endpoint, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -3462,7 +3878,11 @@ func (c *internalClient) GetEndpoint(ctx context.Context, req *GetEndpointReques } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -3508,7 +3928,7 @@ func (c *internalClient) GetEndpoint(ctx context.Context, req *GetEndpointReques } // Retrieves the status of a long-running operation. -func (c *internalClient) getOperation(ctx context.Context, req *GetOperationRequest, opts ...call.Option) (*Operation, error) { +func (c *internalClient) getOperation(ctx context.Context, req GetOperationRequest, opts ...call.Option) (*Operation, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -3522,7 +3942,11 @@ func (c *internalClient) getOperation(ctx context.Context, req *GetOperationRequ } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -3568,7 +3992,7 @@ func (c *internalClient) getOperation(ctx context.Context, req *GetOperationRequ } // Retrieves information about the specified database project. -func (c *internalClient) GetProject(ctx context.Context, req *GetProjectRequest, opts ...call.Option) (*Project, error) { +func (c *internalClient) GetProject(ctx context.Context, req GetProjectRequest, opts ...call.Option) (*Project, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -3582,7 +4006,11 @@ func (c *internalClient) GetProject(ctx context.Context, req *GetProjectRequest, } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -3629,7 +4057,7 @@ func (c *internalClient) GetProject(ctx context.Context, req *GetProjectRequest, // Retrieves information about the specified Postgres role, including its // authentication method and permissions. -func (c *internalClient) GetRole(ctx context.Context, req *GetRoleRequest, opts ...call.Option) (*Role, error) { +func (c *internalClient) GetRole(ctx context.Context, req GetRoleRequest, opts ...call.Option) (*Role, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -3643,7 +4071,11 @@ func (c *internalClient) GetRole(ctx context.Context, req *GetRoleRequest, opts } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -3688,8 +4120,137 @@ func (c *internalClient) GetRole(ctx context.Context, req *GetRoleRequest, opts return resp, nil } +// Retrieves information about the specified snapshot. +func (c *internalClient) GetSnapshot(ctx context.Context, req GetSnapshotRequest, opts ...call.Option) (*Snapshot, error) { + + headers := http.Header{} + headers.Set("Content-Type", "application/json") + if c.workspaceID != "" { + headers.Set("X-Databricks-Workspace-Id", c.workspaceID) + } + + baseURL, err := url.Parse(c.host) + if err != nil { + return nil, err + } + pb := pathBuilder{} + pb.literal("/api/2.0/postgres/") + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } + baseURL.Path, baseURL.RawPath = pb.build() + queryParams := url.Values{} + baseURL.RawQuery = queryParams.Encode() + urlStr := baseURL.String() + + var resp *Snapshot + + call := func(ctx context.Context) error { + httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ + Method: "GET", + URL: urlStr, + Credentials: c.credentials, + UserAgent: c.userAgent, + Headers: headers, + }) + if err != nil { + return err + } + + respBody, _, err := executeHTTPCall(httpCallOptions{ + req: httpReq, + client: c.httpClient, + logger: c.logger, + }) + if err != nil { + return err + } + var wireResp snapshotWire + if err := json.Unmarshal(respBody, &wireResp); err != nil { + return err + } + resp, err = snapshotFromWire(&wireResp) + if err != nil { + return err + } + return nil + } + + if err := executeCall(ctx, call, opts); err != nil { + return nil, err + } + return resp, nil +} + +// Retrieves the snapshot schedule for a branch. A branch with no configured +// schedule returns an empty schedule (not NOT_FOUND). +func (c *internalClient) GetSnapshotSchedule(ctx context.Context, req GetSnapshotScheduleRequest, opts ...call.Option) (*SnapshotSchedule, error) { + + headers := http.Header{} + headers.Set("Content-Type", "application/json") + if c.workspaceID != "" { + headers.Set("X-Databricks-Workspace-Id", c.workspaceID) + } + + baseURL, err := url.Parse(c.host) + if err != nil { + return nil, err + } + pb := pathBuilder{} + pb.literal("/api/2.0/postgres/") + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } + baseURL.Path, baseURL.RawPath = pb.build() + queryParams := url.Values{} + baseURL.RawQuery = queryParams.Encode() + urlStr := baseURL.String() + + var resp *SnapshotSchedule + + call := func(ctx context.Context) error { + httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ + Method: "GET", + URL: urlStr, + Credentials: c.credentials, + UserAgent: c.userAgent, + Headers: headers, + }) + if err != nil { + return err + } + + respBody, _, err := executeHTTPCall(httpCallOptions{ + req: httpReq, + client: c.httpClient, + logger: c.logger, + }) + if err != nil { + return err + } + var wireResp snapshotScheduleWire + if err := json.Unmarshal(respBody, &wireResp); err != nil { + return err + } + resp, err = snapshotScheduleFromWire(&wireResp) + if err != nil { + return err + } + return nil + } + + if err := executeCall(ctx, call, opts); err != nil { + return nil, err + } + return resp, nil +} + // Get a Synced Table. -func (c *internalClient) GetSyncedTable(ctx context.Context, req *GetSyncedTableRequest, opts ...call.Option) (*SyncedTable, error) { +func (c *internalClient) GetSyncedTable(ctx context.Context, req GetSyncedTableRequest, opts ...call.Option) (*SyncedTable, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -3703,7 +4264,11 @@ func (c *internalClient) GetSyncedTable(ctx context.Context, req *GetSyncedTable } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -3749,8 +4314,8 @@ func (c *internalClient) GetSyncedTable(ctx context.Context, req *GetSyncedTable } // Returns a paginated list of database branches in the project. -func (c *internalClient) ListBranches(ctx context.Context, req *ListBranchesRequest, opts ...call.Option) (*ListBranchesResponse, error) { - wireReq, err := listBranchesRequestToWire(req) +func (c *internalClient) ListBranches(ctx context.Context, req ListBranchesRequest, opts ...call.Option) (*ListBranchesResponse, error) { + wireReq, err := listBranchesRequestToWire(&req) if err != nil { return nil, err } @@ -3767,7 +4332,11 @@ func (c *internalClient) ListBranches(ctx context.Context, req *ListBranchesRequ } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/branches") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -3827,7 +4396,7 @@ func (c *internalClient) ListBranches(ctx context.Context, req *ListBranchesRequ // // For example: // -// for item, err := range c.ListBranchesIter(ctx, &ListBranchesRequest{}) { +// for item, err := range c.ListBranchesIter(ctx, ListBranchesRequest{}) { // if err != nil { // return err // } @@ -3839,16 +4408,13 @@ func (c *internalClient) ListBranches(ctx context.Context, req *ListBranchesRequ // // Callers who need custom pagination logic should use // ListBranches directly. -func (c *internalClient) ListBranchesIter(ctx context.Context, req *ListBranchesRequest, opts ...call.Option) iter.Seq2[*Branch, error] { +func (c *internalClient) ListBranchesIter(ctx context.Context, req ListBranchesRequest, opts ...call.Option) iter.Seq2[*Branch, error] { return func(yield func(*Branch, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListBranchesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListBranches(ctx, &pageReq, opts...) + resp, err := c.ListBranches(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -3869,8 +4435,8 @@ func (c *internalClient) ListBranchesIter(ctx context.Context, req *ListBranches // List all CDF configurations for a Lakebase database. Each configuration maps // a Postgres schema to a Unity Catalog schema where the change data feed is // materialized. -func (c *internalClient) ListCdfConfigs(ctx context.Context, req *ListCdfConfigsRequest, opts ...call.Option) (*ListCdfConfigsResponse, error) { - wireReq, err := listCdfConfigsRequestToWire(req) +func (c *internalClient) ListCdfConfigs(ctx context.Context, req ListCdfConfigsRequest, opts ...call.Option) (*ListCdfConfigsResponse, error) { + wireReq, err := listCdfConfigsRequestToWire(&req) if err != nil { return nil, err } @@ -3887,7 +4453,11 @@ func (c *internalClient) ListCdfConfigs(ctx context.Context, req *ListCdfConfigs } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/cdf-configs") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -3944,7 +4514,7 @@ func (c *internalClient) ListCdfConfigs(ctx context.Context, req *ListCdfConfigs // // For example: // -// for item, err := range c.ListCdfConfigsIter(ctx, &ListCdfConfigsRequest{}) { +// for item, err := range c.ListCdfConfigsIter(ctx, ListCdfConfigsRequest{}) { // if err != nil { // return err // } @@ -3956,16 +4526,13 @@ func (c *internalClient) ListCdfConfigs(ctx context.Context, req *ListCdfConfigs // // Callers who need custom pagination logic should use // ListCdfConfigs directly. -func (c *internalClient) ListCdfConfigsIter(ctx context.Context, req *ListCdfConfigsRequest, opts ...call.Option) iter.Seq2[*CdfConfig, error] { +func (c *internalClient) ListCdfConfigsIter(ctx context.Context, req ListCdfConfigsRequest, opts ...call.Option) iter.Seq2[*CdfConfig, error] { return func(yield func(*CdfConfig, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListCdfConfigsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListCdfConfigs(ctx, &pageReq, opts...) + resp, err := c.ListCdfConfigs(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -3986,8 +4553,8 @@ func (c *internalClient) ListCdfConfigsIter(ctx context.Context, req *ListCdfCon // List the per-table CDF statuses within a Lakebase CDF configuration. Each // status shows whether a table's change data feed is snapshotting, streaming, // or skipped. -func (c *internalClient) ListCdfStatuses(ctx context.Context, req *ListCdfStatusesRequest, opts ...call.Option) (*ListCdfStatusesResponse, error) { - wireReq, err := listCdfStatusesRequestToWire(req) +func (c *internalClient) ListCdfStatuses(ctx context.Context, req ListCdfStatusesRequest, opts ...call.Option) (*ListCdfStatusesResponse, error) { + wireReq, err := listCdfStatusesRequestToWire(&req) if err != nil { return nil, err } @@ -4004,7 +4571,11 @@ func (c *internalClient) ListCdfStatuses(ctx context.Context, req *ListCdfStatus } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/cdf-statuses") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -4061,7 +4632,7 @@ func (c *internalClient) ListCdfStatuses(ctx context.Context, req *ListCdfStatus // // For example: // -// for item, err := range c.ListCdfStatusesIter(ctx, &ListCdfStatusesRequest{}) { +// for item, err := range c.ListCdfStatusesIter(ctx, ListCdfStatusesRequest{}) { // if err != nil { // return err // } @@ -4073,16 +4644,13 @@ func (c *internalClient) ListCdfStatuses(ctx context.Context, req *ListCdfStatus // // Callers who need custom pagination logic should use // ListCdfStatuses directly. -func (c *internalClient) ListCdfStatusesIter(ctx context.Context, req *ListCdfStatusesRequest, opts ...call.Option) iter.Seq2[*CdfStatus, error] { +func (c *internalClient) ListCdfStatusesIter(ctx context.Context, req ListCdfStatusesRequest, opts ...call.Option) iter.Seq2[*CdfStatus, error] { return func(yield func(*CdfStatus, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListCdfStatusesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListCdfStatuses(ctx, &pageReq, opts...) + resp, err := c.ListCdfStatuses(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -4101,8 +4669,8 @@ func (c *internalClient) ListCdfStatusesIter(ctx context.Context, req *ListCdfSt } // List Databases. -func (c *internalClient) ListDatabases(ctx context.Context, req *ListDatabasesRequest, opts ...call.Option) (*ListDatabasesResponse, error) { - wireReq, err := listDatabasesRequestToWire(req) +func (c *internalClient) ListDatabases(ctx context.Context, req ListDatabasesRequest, opts ...call.Option) (*ListDatabasesResponse, error) { + wireReq, err := listDatabasesRequestToWire(&req) if err != nil { return nil, err } @@ -4119,7 +4687,11 @@ func (c *internalClient) ListDatabases(ctx context.Context, req *ListDatabasesRe } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/databases") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -4176,7 +4748,7 @@ func (c *internalClient) ListDatabases(ctx context.Context, req *ListDatabasesRe // // For example: // -// for item, err := range c.ListDatabasesIter(ctx, &ListDatabasesRequest{}) { +// for item, err := range c.ListDatabasesIter(ctx, ListDatabasesRequest{}) { // if err != nil { // return err // } @@ -4188,16 +4760,13 @@ func (c *internalClient) ListDatabases(ctx context.Context, req *ListDatabasesRe // // Callers who need custom pagination logic should use // ListDatabases directly. -func (c *internalClient) ListDatabasesIter(ctx context.Context, req *ListDatabasesRequest, opts ...call.Option) iter.Seq2[*Database, error] { +func (c *internalClient) ListDatabasesIter(ctx context.Context, req ListDatabasesRequest, opts ...call.Option) iter.Seq2[*Database, error] { return func(yield func(*Database, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListDatabasesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListDatabases(ctx, &pageReq, opts...) + resp, err := c.ListDatabases(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -4216,8 +4785,8 @@ func (c *internalClient) ListDatabasesIter(ctx context.Context, req *ListDatabas } // Returns a paginated list of compute endpoints in the branch. -func (c *internalClient) ListEndpoints(ctx context.Context, req *ListEndpointsRequest, opts ...call.Option) (*ListEndpointsResponse, error) { - wireReq, err := listEndpointsRequestToWire(req) +func (c *internalClient) ListEndpoints(ctx context.Context, req ListEndpointsRequest, opts ...call.Option) (*ListEndpointsResponse, error) { + wireReq, err := listEndpointsRequestToWire(&req) if err != nil { return nil, err } @@ -4234,7 +4803,11 @@ func (c *internalClient) ListEndpoints(ctx context.Context, req *ListEndpointsRe } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/endpoints") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -4291,7 +4864,7 @@ func (c *internalClient) ListEndpoints(ctx context.Context, req *ListEndpointsRe // // For example: // -// for item, err := range c.ListEndpointsIter(ctx, &ListEndpointsRequest{}) { +// for item, err := range c.ListEndpointsIter(ctx, ListEndpointsRequest{}) { // if err != nil { // return err // } @@ -4303,16 +4876,13 @@ func (c *internalClient) ListEndpoints(ctx context.Context, req *ListEndpointsRe // // Callers who need custom pagination logic should use // ListEndpoints directly. -func (c *internalClient) ListEndpointsIter(ctx context.Context, req *ListEndpointsRequest, opts ...call.Option) iter.Seq2[*Endpoint, error] { +func (c *internalClient) ListEndpointsIter(ctx context.Context, req ListEndpointsRequest, opts ...call.Option) iter.Seq2[*Endpoint, error] { return func(yield func(*Endpoint, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListEndpointsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListEndpoints(ctx, &pageReq, opts...) + resp, err := c.ListEndpoints(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -4332,8 +4902,8 @@ func (c *internalClient) ListEndpointsIter(ctx context.Context, req *ListEndpoin // Returns a paginated list of database projects in the workspace that the user // has permission to access. -func (c *internalClient) ListProjects(ctx context.Context, req *ListProjectsRequest, opts ...call.Option) (*ListProjectsResponse, error) { - wireReq, err := listProjectsRequestToWire(req) +func (c *internalClient) ListProjects(ctx context.Context, req ListProjectsRequest, opts ...call.Option) (*ListProjectsResponse, error) { + wireReq, err := listProjectsRequestToWire(&req) if err != nil { return nil, err } @@ -4406,7 +4976,7 @@ func (c *internalClient) ListProjects(ctx context.Context, req *ListProjectsRequ // // For example: // -// for item, err := range c.ListProjectsIter(ctx, &ListProjectsRequest{}) { +// for item, err := range c.ListProjectsIter(ctx, ListProjectsRequest{}) { // if err != nil { // return err // } @@ -4418,16 +4988,13 @@ func (c *internalClient) ListProjects(ctx context.Context, req *ListProjectsRequ // // Callers who need custom pagination logic should use // ListProjects directly. -func (c *internalClient) ListProjectsIter(ctx context.Context, req *ListProjectsRequest, opts ...call.Option) iter.Seq2[*Project, error] { +func (c *internalClient) ListProjectsIter(ctx context.Context, req ListProjectsRequest, opts ...call.Option) iter.Seq2[*Project, error] { return func(yield func(*Project, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListProjectsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListProjects(ctx, &pageReq, opts...) + resp, err := c.ListProjects(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -4446,8 +5013,8 @@ func (c *internalClient) ListProjectsIter(ctx context.Context, req *ListProjects } // Returns a paginated list of Postgres roles in the branch. -func (c *internalClient) ListRoles(ctx context.Context, req *ListRolesRequest, opts ...call.Option) (*ListRolesResponse, error) { - wireReq, err := listRolesRequestToWire(req) +func (c *internalClient) ListRoles(ctx context.Context, req ListRolesRequest, opts ...call.Option) (*ListRolesResponse, error) { + wireReq, err := listRolesRequestToWire(&req) if err != nil { return nil, err } @@ -4464,7 +5031,11 @@ func (c *internalClient) ListRoles(ctx context.Context, req *ListRolesRequest, o } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/roles") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -4521,7 +5092,7 @@ func (c *internalClient) ListRoles(ctx context.Context, req *ListRolesRequest, o // // For example: // -// for item, err := range c.ListRolesIter(ctx, &ListRolesRequest{}) { +// for item, err := range c.ListRolesIter(ctx, ListRolesRequest{}) { // if err != nil { // return err // } @@ -4533,16 +5104,13 @@ func (c *internalClient) ListRoles(ctx context.Context, req *ListRolesRequest, o // // Callers who need custom pagination logic should use // ListRoles directly. -func (c *internalClient) ListRolesIter(ctx context.Context, req *ListRolesRequest, opts ...call.Option) iter.Seq2[*Role, error] { +func (c *internalClient) ListRolesIter(ctx context.Context, req ListRolesRequest, opts ...call.Option) iter.Seq2[*Role, error] { return func(yield func(*Role, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListRolesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListRoles(ctx, &pageReq, opts...) + resp, err := c.ListRoles(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -4560,9 +5128,125 @@ func (c *internalClient) ListRolesIter(ctx context.Context, req *ListRolesReques } } +// Returns a paginated list of snapshots in the project. +func (c *internalClient) ListSnapshots(ctx context.Context, req ListSnapshotsRequest, opts ...call.Option) (*ListSnapshotsResponse, error) { + wireReq, err := listSnapshotsRequestToWire(&req) + if err != nil { + return nil, err + } + + headers := http.Header{} + headers.Set("Content-Type", "application/json") + if c.workspaceID != "" { + headers.Set("X-Databricks-Workspace-Id", c.workspaceID) + } + + baseURL, err := url.Parse(c.host) + if err != nil { + return nil, err + } + pb := pathBuilder{} + pb.literal("/api/2.0/postgres/") + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } + pb.literal("/snapshots") + baseURL.Path, baseURL.RawPath = pb.build() + queryParams := url.Values{} + if err := addQueryValue(queryParams, "page_token", wireReq.PageToken); err != nil { + return nil, err + } + if err := addQueryValue(queryParams, "page_size", wireReq.PageSize); err != nil { + return nil, err + } + baseURL.RawQuery = queryParams.Encode() + urlStr := baseURL.String() + + var resp *ListSnapshotsResponse + + call := func(ctx context.Context) error { + httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ + Method: "GET", + URL: urlStr, + Credentials: c.credentials, + UserAgent: c.userAgent, + Headers: headers, + }) + if err != nil { + return err + } + + respBody, _, err := executeHTTPCall(httpCallOptions{ + req: httpReq, + client: c.httpClient, + logger: c.logger, + }) + if err != nil { + return err + } + var wireResp listSnapshotsResponseWire + if err := json.Unmarshal(respBody, &wireResp); err != nil { + return err + } + resp, err = listSnapshotsResponseFromWire(&wireResp) + if err != nil { + return err + } + return nil + } + + if err := executeCall(ctx, call, opts); err != nil { + return nil, err + } + return resp, nil +} + +// ListSnapshotsIter returns an iterator that iterates +// over the results of ListSnapshots. +// +// For example: +// +// for item, err := range c.ListSnapshotsIter(ctx, ListSnapshotsRequest{}) { +// if err != nil { +// return err +// } +// fmt.Println(item) +// } +// +// Options opts are passed to each ListSnapshots call +// made by the iterator under the hood. +// +// Callers who need custom pagination logic should use +// ListSnapshots directly. +func (c *internalClient) ListSnapshotsIter(ctx context.Context, req ListSnapshotsRequest, opts ...call.Option) iter.Seq2[*Snapshot, error] { + return func(yield func(*Snapshot, error) bool) { + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req + for { + resp, err := c.ListSnapshots(ctx, pageReq, opts...) + if err != nil { + yield(nil, err) + return + } + for i := range resp.Snapshots { + if !yield(&resp.Snapshots[i], nil) { + return + } + } + if resp.NextPageToken == nil || *resp.NextPageToken == "" { + return + } + pageReq.PageToken = resp.NextPageToken + } + } +} + // Undeletes the specified database branch. -func (c *internalClient) undeleteBranchBase(ctx context.Context, req *UndeleteBranchRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := undeleteBranchRequestToWire(req) +func (c *internalClient) undeleteBranchBase(ctx context.Context, req UndeleteBranchRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := undeleteBranchRequestToWire(&req) if err != nil { return nil, err } @@ -4583,7 +5267,11 @@ func (c *internalClient) undeleteBranchBase(ctx context.Context, req *UndeleteBr } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/undelete") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -4631,7 +5319,7 @@ func (c *internalClient) undeleteBranchBase(ctx context.Context, req *UndeleteBr } // Undeletes the specified database branch. -func (c *internalClient) UndeleteBranch(ctx context.Context, req *UndeleteBranchRequest, opts ...call.Option) (*UndeleteBranchOperation, error) { +func (c *internalClient) UndeleteBranch(ctx context.Context, req UndeleteBranchRequest, opts ...call.Option) (*UndeleteBranchOperation, error) { operation, err := c.undeleteBranchBase(ctx, req, opts...) if err != nil { return nil, err @@ -4648,7 +5336,7 @@ func (c *internalClient) UndeleteBranch(ctx context.Context, req *UndeleteBranch // UndeleteBranchOperation tracks the state of the long-running operation started by UndeleteBranch. type UndeleteBranchOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -4674,7 +5362,7 @@ func (o *UndeleteBranchOperation) Metadata() (*BranchOperationMetadata, error) { // Done refreshes the operation and reports whether it has completed. func (o *UndeleteBranchOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -4691,7 +5379,7 @@ func (o *UndeleteBranchOperation) Done(ctx context.Context, opts ...call.Option) // Wait polls the operation until it completes. func (o *UndeleteBranchOperation) Wait(ctx context.Context, opts ...lro.Option) error { poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -4721,8 +5409,8 @@ func (o *UndeleteBranchOperation) Wait(ctx context.Context, opts ...lro.Option) } // Undeletes a soft-deleted project. -func (c *internalClient) undeleteProjectBase(ctx context.Context, req *UndeleteProjectRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := undeleteProjectRequestToWire(req) +func (c *internalClient) undeleteProjectBase(ctx context.Context, req UndeleteProjectRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := undeleteProjectRequestToWire(&req) if err != nil { return nil, err } @@ -4743,7 +5431,11 @@ func (c *internalClient) undeleteProjectBase(ctx context.Context, req *UndeleteP } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/undelete") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -4791,7 +5483,7 @@ func (c *internalClient) undeleteProjectBase(ctx context.Context, req *UndeleteP } // Undeletes a soft-deleted project. -func (c *internalClient) UndeleteProject(ctx context.Context, req *UndeleteProjectRequest, opts ...call.Option) (*UndeleteProjectOperation, error) { +func (c *internalClient) UndeleteProject(ctx context.Context, req UndeleteProjectRequest, opts ...call.Option) (*UndeleteProjectOperation, error) { operation, err := c.undeleteProjectBase(ctx, req, opts...) if err != nil { return nil, err @@ -4808,7 +5500,7 @@ func (c *internalClient) UndeleteProject(ctx context.Context, req *UndeleteProje // UndeleteProjectOperation tracks the state of the long-running operation started by UndeleteProject. type UndeleteProjectOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -4834,7 +5526,7 @@ func (o *UndeleteProjectOperation) Metadata() (*ProjectOperationMetadata, error) // Done refreshes the operation and reports whether it has completed. func (o *UndeleteProjectOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -4851,7 +5543,7 @@ func (o *UndeleteProjectOperation) Done(ctx context.Context, opts ...call.Option // Wait polls the operation until it completes. func (o *UndeleteProjectOperation) Wait(ctx context.Context, opts ...lro.Option) error { poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -4882,8 +5574,8 @@ func (o *UndeleteProjectOperation) Wait(ctx context.Context, opts ...lro.Option) // Updates the specified database branch. You can set this branch as the // project's default branch, or protect/unprotect it. -func (c *internalClient) updateBranchBase(ctx context.Context, req *UpdateBranchRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := updateBranchRequestToWire(req) +func (c *internalClient) updateBranchBase(ctx context.Context, req UpdateBranchRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := updateBranchRequestToWire(&req) if err != nil { return nil, err } @@ -4904,7 +5596,11 @@ func (c *internalClient) updateBranchBase(ctx context.Context, req *UpdateBranch } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Branch.Name) + if req.Branch == nil || req.Branch.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Branch.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -4955,7 +5651,7 @@ func (c *internalClient) updateBranchBase(ctx context.Context, req *UpdateBranch // Updates the specified database branch. You can set this branch as the // project's default branch, or protect/unprotect it. -func (c *internalClient) UpdateBranch(ctx context.Context, req *UpdateBranchRequest, opts ...call.Option) (*UpdateBranchOperation, error) { +func (c *internalClient) UpdateBranch(ctx context.Context, req UpdateBranchRequest, opts ...call.Option) (*UpdateBranchOperation, error) { operation, err := c.updateBranchBase(ctx, req, opts...) if err != nil { return nil, err @@ -4972,7 +5668,7 @@ func (c *internalClient) UpdateBranch(ctx context.Context, req *UpdateBranchRequ // UpdateBranchOperation tracks the state of the long-running operation started by UpdateBranch. type UpdateBranchOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -4998,7 +5694,7 @@ func (o *UpdateBranchOperation) Metadata() (*BranchOperationMetadata, error) { // Done refreshes the operation and reports whether it has completed. func (o *UpdateBranchOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -5016,7 +5712,7 @@ func (o *UpdateBranchOperation) Done(ctx context.Context, opts ...call.Option) ( func (o *UpdateBranchOperation) Wait(ctx context.Context, opts ...lro.Option) (*Branch, error) { var result *Branch poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -5054,8 +5750,8 @@ func (o *UpdateBranchOperation) Wait(ctx context.Context, opts ...lro.Option) (* } // Update Data API configuration for a database. -func (c *internalClient) updateDataApiBase(ctx context.Context, req *UpdateDataApiRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := updateDataApiRequestToWire(req) +func (c *internalClient) updateDataApiBase(ctx context.Context, req UpdateDataApiRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := updateDataApiRequestToWire(&req) if err != nil { return nil, err } @@ -5076,7 +5772,11 @@ func (c *internalClient) updateDataApiBase(ctx context.Context, req *UpdateDataA } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.DataApi.Name) + if req.DataApi == nil || req.DataApi.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DataApi.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -5126,7 +5826,7 @@ func (c *internalClient) updateDataApiBase(ctx context.Context, req *UpdateDataA } // Update Data API configuration for a database. -func (c *internalClient) UpdateDataApi(ctx context.Context, req *UpdateDataApiRequest, opts ...call.Option) (*UpdateDataApiOperation, error) { +func (c *internalClient) UpdateDataApi(ctx context.Context, req UpdateDataApiRequest, opts ...call.Option) (*UpdateDataApiOperation, error) { operation, err := c.updateDataApiBase(ctx, req, opts...) if err != nil { return nil, err @@ -5143,7 +5843,7 @@ func (c *internalClient) UpdateDataApi(ctx context.Context, req *UpdateDataApiRe // UpdateDataApiOperation tracks the state of the long-running operation started by UpdateDataApi. type UpdateDataApiOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -5169,7 +5869,7 @@ func (o *UpdateDataApiOperation) Metadata() (*DataApiOperationMetadata, error) { // Done refreshes the operation and reports whether it has completed. func (o *UpdateDataApiOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -5187,7 +5887,7 @@ func (o *UpdateDataApiOperation) Done(ctx context.Context, opts ...call.Option) func (o *UpdateDataApiOperation) Wait(ctx context.Context, opts ...lro.Option) (*DataApi, error) { var result *DataApi poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -5225,8 +5925,8 @@ func (o *UpdateDataApiOperation) Wait(ctx context.Context, opts ...lro.Option) ( } // Update a Database. -func (c *internalClient) updateDatabaseBase(ctx context.Context, req *UpdateDatabaseRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := updateDatabaseRequestToWire(req) +func (c *internalClient) updateDatabaseBase(ctx context.Context, req UpdateDatabaseRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := updateDatabaseRequestToWire(&req) if err != nil { return nil, err } @@ -5247,7 +5947,11 @@ func (c *internalClient) updateDatabaseBase(ctx context.Context, req *UpdateData } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Database.Name) + if req.Database == nil || req.Database.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Database.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -5297,7 +6001,7 @@ func (c *internalClient) updateDatabaseBase(ctx context.Context, req *UpdateData } // Update a Database. -func (c *internalClient) UpdateDatabase(ctx context.Context, req *UpdateDatabaseRequest, opts ...call.Option) (*UpdateDatabaseOperation, error) { +func (c *internalClient) UpdateDatabase(ctx context.Context, req UpdateDatabaseRequest, opts ...call.Option) (*UpdateDatabaseOperation, error) { operation, err := c.updateDatabaseBase(ctx, req, opts...) if err != nil { return nil, err @@ -5314,7 +6018,7 @@ func (c *internalClient) UpdateDatabase(ctx context.Context, req *UpdateDatabase // UpdateDatabaseOperation tracks the state of the long-running operation started by UpdateDatabase. type UpdateDatabaseOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -5340,7 +6044,7 @@ func (o *UpdateDatabaseOperation) Metadata() (*DatabaseOperationMetadata, error) // Done refreshes the operation and reports whether it has completed. func (o *UpdateDatabaseOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -5358,7 +6062,7 @@ func (o *UpdateDatabaseOperation) Done(ctx context.Context, opts ...call.Option) func (o *UpdateDatabaseOperation) Wait(ctx context.Context, opts ...lro.Option) (*Database, error) { var result *Database poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -5397,8 +6101,8 @@ func (o *UpdateDatabaseOperation) Wait(ctx context.Context, opts ...lro.Option) // Updates the specified compute endpoint. You can update autoscaling limits, // suspend timeout, or enable/disable the compute endpoint. -func (c *internalClient) updateEndpointBase(ctx context.Context, req *UpdateEndpointRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := updateEndpointRequestToWire(req) +func (c *internalClient) updateEndpointBase(ctx context.Context, req UpdateEndpointRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := updateEndpointRequestToWire(&req) if err != nil { return nil, err } @@ -5419,7 +6123,11 @@ func (c *internalClient) updateEndpointBase(ctx context.Context, req *UpdateEndp } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Endpoint.Name) + if req.Endpoint == nil || req.Endpoint.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Endpoint.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -5470,7 +6178,7 @@ func (c *internalClient) updateEndpointBase(ctx context.Context, req *UpdateEndp // Updates the specified compute endpoint. You can update autoscaling limits, // suspend timeout, or enable/disable the compute endpoint. -func (c *internalClient) UpdateEndpoint(ctx context.Context, req *UpdateEndpointRequest, opts ...call.Option) (*UpdateEndpointOperation, error) { +func (c *internalClient) UpdateEndpoint(ctx context.Context, req UpdateEndpointRequest, opts ...call.Option) (*UpdateEndpointOperation, error) { operation, err := c.updateEndpointBase(ctx, req, opts...) if err != nil { return nil, err @@ -5487,7 +6195,7 @@ func (c *internalClient) UpdateEndpoint(ctx context.Context, req *UpdateEndpoint // UpdateEndpointOperation tracks the state of the long-running operation started by UpdateEndpoint. type UpdateEndpointOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -5513,7 +6221,7 @@ func (o *UpdateEndpointOperation) Metadata() (*EndpointOperationMetadata, error) // Done refreshes the operation and reports whether it has completed. func (o *UpdateEndpointOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -5531,7 +6239,7 @@ func (o *UpdateEndpointOperation) Done(ctx context.Context, opts ...call.Option) func (o *UpdateEndpointOperation) Wait(ctx context.Context, opts ...lro.Option) (*Endpoint, error) { var result *Endpoint poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -5569,8 +6277,8 @@ func (o *UpdateEndpointOperation) Wait(ctx context.Context, opts ...lro.Option) } // Updates the specified database project. -func (c *internalClient) updateProjectBase(ctx context.Context, req *UpdateProjectRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := updateProjectRequestToWire(req) +func (c *internalClient) updateProjectBase(ctx context.Context, req UpdateProjectRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := updateProjectRequestToWire(&req) if err != nil { return nil, err } @@ -5591,7 +6299,11 @@ func (c *internalClient) updateProjectBase(ctx context.Context, req *UpdateProje } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Project.Name) + if req.Project == nil || req.Project.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Project.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -5641,7 +6353,7 @@ func (c *internalClient) updateProjectBase(ctx context.Context, req *UpdateProje } // Updates the specified database project. -func (c *internalClient) UpdateProject(ctx context.Context, req *UpdateProjectRequest, opts ...call.Option) (*UpdateProjectOperation, error) { +func (c *internalClient) UpdateProject(ctx context.Context, req UpdateProjectRequest, opts ...call.Option) (*UpdateProjectOperation, error) { operation, err := c.updateProjectBase(ctx, req, opts...) if err != nil { return nil, err @@ -5658,7 +6370,7 @@ func (c *internalClient) UpdateProject(ctx context.Context, req *UpdateProjectRe // UpdateProjectOperation tracks the state of the long-running operation started by UpdateProject. type UpdateProjectOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -5684,7 +6396,7 @@ func (o *UpdateProjectOperation) Metadata() (*ProjectOperationMetadata, error) { // Done refreshes the operation and reports whether it has completed. func (o *UpdateProjectOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -5702,7 +6414,7 @@ func (o *UpdateProjectOperation) Done(ctx context.Context, opts ...call.Option) func (o *UpdateProjectOperation) Wait(ctx context.Context, opts ...lro.Option) (*Project, error) { var result *Project poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -5740,8 +6452,8 @@ func (o *UpdateProjectOperation) Wait(ctx context.Context, opts ...lro.Option) ( } // Update a role for a branch. -func (c *internalClient) updateRoleBase(ctx context.Context, req *UpdateRoleRequest, opts ...call.Option) (*Operation, error) { - wireReq, err := updateRoleRequestToWire(req) +func (c *internalClient) updateRoleBase(ctx context.Context, req UpdateRoleRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := updateRoleRequestToWire(&req) if err != nil { return nil, err } @@ -5762,7 +6474,11 @@ func (c *internalClient) updateRoleBase(ctx context.Context, req *UpdateRoleRequ } pb := pathBuilder{} pb.literal("/api/2.0/postgres/") - pb.singleSegment(*req.Role.Name) + if req.Role == nil || req.Role.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Role.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -5812,7 +6528,7 @@ func (c *internalClient) updateRoleBase(ctx context.Context, req *UpdateRoleRequ } // Update a role for a branch. -func (c *internalClient) UpdateRole(ctx context.Context, req *UpdateRoleRequest, opts ...call.Option) (*UpdateRoleOperation, error) { +func (c *internalClient) UpdateRole(ctx context.Context, req UpdateRoleRequest, opts ...call.Option) (*UpdateRoleOperation, error) { operation, err := c.updateRoleBase(ctx, req, opts...) if err != nil { return nil, err @@ -5829,7 +6545,7 @@ func (c *internalClient) UpdateRole(ctx context.Context, req *UpdateRoleRequest, // UpdateRoleOperation tracks the state of the long-running operation started by UpdateRole. type UpdateRoleOperation struct { operation *Operation - getOperation func(context.Context, *GetOperationRequest, ...call.Option) (*Operation, error) + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) } // Name returns the server-assigned operation name. @@ -5855,7 +6571,7 @@ func (o *UpdateRoleOperation) Metadata() (*RoleOperationMetadata, error) { // Done refreshes the operation and reports whether it has completed. func (o *UpdateRoleOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}, opts...) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) if err != nil { return false, err } @@ -5873,7 +6589,7 @@ func (o *UpdateRoleOperation) Done(ctx context.Context, opts ...call.Option) (bo func (o *UpdateRoleOperation) Wait(ctx context.Context, opts ...lro.Option) (*Role, error) { var result *Role poll := func(ctx context.Context) error { - operation, err := o.getOperation(ctx, &GetOperationRequest{Name: o.operation.Name}) + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) if err != nil { return err } @@ -5909,3 +6625,180 @@ func (o *UpdateRoleOperation) Wait(ctx context.Context, opts ...lro.Option) (*Ro } return result, nil } + +// Sets the snapshot schedule for a branch. The `schedule` field is replaced +// wholesale; an empty schedule disables automatic snapshots. +func (c *internalClient) updateSnapshotScheduleBase(ctx context.Context, req UpdateSnapshotScheduleRequest, opts ...call.Option) (*Operation, error) { + wireReq, err := updateSnapshotScheduleRequestToWire(&req) + if err != nil { + return nil, err + } + body, err := json.Marshal(wireReq.SnapshotSchedule) + if err != nil { + return nil, err + } + + headers := http.Header{} + headers.Set("Content-Type", "application/json") + if c.workspaceID != "" { + headers.Set("X-Databricks-Workspace-Id", c.workspaceID) + } + + baseURL, err := url.Parse(c.host) + if err != nil { + return nil, err + } + pb := pathBuilder{} + pb.literal("/api/2.0/postgres/") + if req.SnapshotSchedule == nil || req.SnapshotSchedule.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SnapshotSchedule.Name) + } + baseURL.Path, baseURL.RawPath = pb.build() + queryParams := url.Values{} + if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { + return nil, err + } + baseURL.RawQuery = queryParams.Encode() + urlStr := baseURL.String() + + var resp *Operation + + call := func(ctx context.Context) error { + httpReq, err := newHTTPRequest(ctx, httpRequestOptions{ + Method: "PATCH", + URL: urlStr, + Credentials: c.credentials, + UserAgent: c.userAgent, + Headers: headers, + Body: bytes.NewBuffer(body), + }) + if err != nil { + return err + } + + respBody, _, err := executeHTTPCall(httpCallOptions{ + req: httpReq, + client: c.httpClient, + logger: c.logger, + }) + if err != nil { + return err + } + var wireResp operationWire + if err := json.Unmarshal(respBody, &wireResp); err != nil { + return err + } + resp, err = operationFromWire(&wireResp) + if err != nil { + return err + } + return nil + } + + if err := executeCall(ctx, call, opts); err != nil { + return nil, err + } + return resp, nil +} + +// Sets the snapshot schedule for a branch. The `schedule` field is replaced +// wholesale; an empty schedule disables automatic snapshots. +func (c *internalClient) UpdateSnapshotSchedule(ctx context.Context, req UpdateSnapshotScheduleRequest, opts ...call.Option) (*UpdateSnapshotScheduleOperation, error) { + operation, err := c.updateSnapshotScheduleBase(ctx, req, opts...) + if err != nil { + return nil, err + } + if err := validateOperationName(operation.Name); err != nil { + return nil, err + } + return &UpdateSnapshotScheduleOperation{ + operation: operation, + getOperation: c.getOperation, + }, nil +} + +// UpdateSnapshotScheduleOperation tracks the state of the long-running operation started by UpdateSnapshotSchedule. +type UpdateSnapshotScheduleOperation struct { + operation *Operation + getOperation func(context.Context, GetOperationRequest, ...call.Option) (*Operation, error) +} + +// Name returns the server-assigned operation name. +func (o *UpdateSnapshotScheduleOperation) Name() *string { + return o.operation.Name +} + +// Metadata returns metadata associated with the operation. +func (o *UpdateSnapshotScheduleOperation) Metadata() (*SnapshotScheduleOperationMetadata, error) { + if len(o.operation.Metadata) == 0 || bytes.Equal(bytes.TrimSpace(o.operation.Metadata), []byte("null")) { + return nil, nil + } + var metadata snapshotScheduleOperationMetadataWire + if err := json.Unmarshal(o.operation.Metadata, &metadata); err != nil { + return nil, fmt.Errorf("decode operation metadata: %w", err) + } + converted, err := snapshotScheduleOperationMetadataFromWire(&metadata) + if err != nil { + return nil, err + } + return converted, nil +} + +// Done refreshes the operation and reports whether it has completed. +func (o *UpdateSnapshotScheduleOperation) Done(ctx context.Context, opts ...call.Option) (bool, error) { + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}, opts...) + if err != nil { + return false, err + } + if err := validateOperationName(operation.Name); err != nil { + return false, err + } + o.operation = operation + if operation.Done == nil { + return false, fmt.Errorf("invalid operation response: missing done field") + } + return *operation.Done, nil +} + +// Wait polls the operation until it completes. +func (o *UpdateSnapshotScheduleOperation) Wait(ctx context.Context, opts ...lro.Option) (*SnapshotSchedule, error) { + var result *SnapshotSchedule + poll := func(ctx context.Context) error { + operation, err := o.getOperation(ctx, GetOperationRequest{Name: o.operation.Name}) + if err != nil { + return err + } + if err := validateOperationName(operation.Name); err != nil { + return err + } + o.operation = operation + if operation.Done == nil { + return fmt.Errorf("invalid operation response: missing done field") + } + if !*operation.Done { + return errOperationStillRunning + } + if operationError, ok := operation.Result.(*Operation_Result_Error); ok && operationError != nil { + return fmt.Errorf("operation failed: %w", &operationError.Error) + } + operationResponse, ok := operation.Result.(*Operation_Result_Response) + if !ok || operationResponse == nil || len(operationResponse.Response) == 0 || bytes.Equal(bytes.TrimSpace(operationResponse.Response), []byte("null")) { + return fmt.Errorf("operation completed without a response") + } + var response snapshotScheduleWire + if err := json.Unmarshal(operationResponse.Response, &response); err != nil { + return fmt.Errorf("decode operation response: %w", err) + } + result, err = snapshotScheduleFromWire(&response) + if err != nil { + return err + } + return nil + } + if err := executeWait(ctx, poll, opts...); err != nil { + return nil, err + } + return result, nil +} diff --git a/postgres/v1/genhelper.go b/postgres/v1/genhelper.go old mode 100755 new mode 100644 index c1c01f1..be0dd5e --- a/postgres/v1/genhelper.go +++ b/postgres/v1/genhelper.go @@ -206,11 +206,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -223,13 +224,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/postgres/v1/model.go b/postgres/v1/model.go old mode 100755 new mode 100644 index 94b71a3..3e7b7bc --- a/postgres/v1/model.go +++ b/postgres/v1/model.go @@ -28,6 +28,27 @@ const ( CdfState_CdfStateSkipped CdfState = "CDF_STATE_SKIPPED" ) +// The day of the week on which a weekly snapshot is taken. +type DayOfWeek string + +const ( + DayOfWeek_Unspecified DayOfWeek = "" + // Monday. + DayOfWeek_Monday DayOfWeek = "MONDAY" + // Tuesday. + DayOfWeek_Tuesday DayOfWeek = "TUESDAY" + // Wednesday. + DayOfWeek_Wednesday DayOfWeek = "WEDNESDAY" + // Thursday. + DayOfWeek_Thursday DayOfWeek = "THURSDAY" + // Friday. + DayOfWeek_Friday DayOfWeek = "FRIDAY" + // Saturday. + DayOfWeek_Saturday DayOfWeek = "SATURDAY" + // Sunday. + DayOfWeek_Sunday DayOfWeek = "SUNDAY" +) + // The compute endpoint type. Either `read_write` or `read_only`. type EndpointType string @@ -706,7 +727,13 @@ type BranchSpec struct { // // When updating this field, use "spec.expiration" in the update_mask. Expiration isBranchSpec_Expiration - _ [0]branchSpecExpirationFieldMaskMetadata `fieldmask_oneof:"Expiration"` + // The snapshot this branch was created from. When set, the branch's data comes + // from the snapshot rather than a source branch, so source_branch, + // source_branch_lsn, and source_branch_time must be empty. The snapshot must be + // AVAILABLE and belong to this branch's project. Format: + // projects/{project_id}/snapshots/{snapshot_id} + SourceSnapshot *string `fieldmask:"source_snapshot"` + _ [0]branchSpecExpirationFieldMaskMetadata `fieldmask_oneof:"Expiration"` } type isBranchSpec_Expiration interface { @@ -782,6 +809,10 @@ type BranchStatus struct { // A timestamp indicating when the branch is scheduled to be purged. Empty if // the branch is not deleted, otherwise set to a timestamp in the future. PurgeTime *types.Time `fieldmask:"purge_time"` + // The snapshot this branch was restored from. Set only for branches created by + // restoring a snapshot; unset for all other branches. Format: + // projects/{project_id}/snapshots/{snapshot_id} + SourceSnapshot *string `fieldmask:"source_snapshot"` } type Catalog struct { @@ -1023,6 +1054,16 @@ type CreateRoleRequest struct { ReplaceExisting *bool } +type CreateSnapshotRequest struct { + // The project in which to create the snapshot. Format: projects/{project_id} + Parent *string + // The snapshot to create. + Snapshot *Snapshot + // Client-chosen ID for the snapshot. It becomes the final segment of the + // snapshot resource name and cannot be changed after creation. + SnapshotId *string +} + // Establish a synchronisation to the Postgres database for Reverse ETL for the // source table selected from the Unity Catalog.. type CreateSyncedTableRequest struct { @@ -1042,6 +1083,12 @@ type CreateSyncedTableRequest struct { SyncedTable *SyncedTable } +// Take a snapshot once per day, at the configured hour.. +type DailySchedule struct { + // The hour of the day, in UTC, at which to take the snapshot, in [0, 23]. + Hour *int +} + // DataApi represents the Data API (PostgREST) configuration for a Database. At // most one DataApi per database. Create enables Data API, Delete disables it.. type DataApi struct { @@ -1243,6 +1290,12 @@ type DeleteRoleRequest struct { ReassignOwnedTo *string } +type DeleteSnapshotRequest struct { + // The resource name of the snapshot to delete. Format: + // projects/{project_id}/snapshots/{snapshot_id} + Name *string +} + type DeleteSyncedTableRequest struct { // The Full resource name of the synced table, of the format // "synced_tables/{catalog}.{schema}.{table}", where (catalog, schema, table) @@ -1526,6 +1579,19 @@ type GetRoleRequest struct { Name *string } +type GetSnapshotRequest struct { + // The resource name of the snapshot to retrieve. Format: + // projects/{project_id}/snapshots/{snapshot_id} + Name *string +} + +// Request to retrieve the snapshot schedule for a branch.. +type GetSnapshotScheduleRequest struct { + // The resource name of the branch's snapshot schedule. Format: + // projects/{project_id}/branches/{branch_id}/snapshot-schedule + Name *string +} + type GetSyncedTableRequest struct { // The Full resource name of the synced table. Format: // "synced_tables/{catalog}.{schema}.{table}", where (catalog, schema, table) @@ -1717,6 +1783,32 @@ type ListRolesResponse struct { NextPageToken *string } +type ListSnapshotsRequest struct { + // The project that owns the snapshots. Format: projects/{project_id} + Parent *string + // Page token from a previous response; omit for the first page. + PageToken *string + // Maximum number of snapshots to return per page. + PageSize *int +} + +type ListSnapshotsResponse struct { + // The snapshots in the project. + Snapshots []Snapshot + // Token to retrieve the next page; empty if there are no more pages. + NextPageToken *string +} + +// Take a snapshot once per month, on the configured day at the configured hour.. +type MonthlySchedule struct { + // The day of the month on which to take the snapshot, in [1, 31]. In shorter + // months the snapshot is taken on the last day instead (day 31 runs on Feb 28 + // or 29, and on Apr 30), so every month gets exactly one snapshot. + Day *int + // The hour of the day, in UTC, at which to take the snapshot, in [0, 23]. + Hour *int +} + type NewPipelineSpec struct { // UC catalog for the pipeline to store intermediate files (checkpoints, event // logs etc). This needs to be a standard catalog where the user has permissions @@ -2050,6 +2142,187 @@ type Role_RoleStatus struct { type RoleOperationMetadata struct { } +// One cadence at which automatic snapshots are taken.. +type ScheduleCadence struct { + // The recurrence pattern. Exactly one arm must be set; an unset cadence is + // rejected with INVALID_PARAMETER_VALUE. + Schedule isScheduleCadence_Schedule + // How long snapshots from this cadence are kept before automatic deletion. Must + // be at least 1 hour. Applied when a snapshot is taken; not retroactive, so + // changing it affects only later snapshots. + Retention *types.Duration +} + +type isScheduleCadence_Schedule interface { + isScheduleCadence_Schedule() +} + +// ScheduleCadence_Schedule_DailySchedule selects DailySchedule for ScheduleCadence.Schedule. +// Take a snapshot once per day. +type ScheduleCadence_Schedule_DailySchedule struct { + DailySchedule DailySchedule +} + +func (*ScheduleCadence_Schedule_DailySchedule) isScheduleCadence_Schedule() {} + +// ScheduleCadence_Schedule_WeeklySchedule selects WeeklySchedule for ScheduleCadence.Schedule. +// Take a snapshot once per week. +type ScheduleCadence_Schedule_WeeklySchedule struct { + WeeklySchedule WeeklySchedule +} + +func (*ScheduleCadence_Schedule_WeeklySchedule) isScheduleCadence_Schedule() {} + +// ScheduleCadence_Schedule_MonthlySchedule selects MonthlySchedule for ScheduleCadence.Schedule. +// Take a snapshot once per month. +type ScheduleCadence_Schedule_MonthlySchedule struct { + MonthlySchedule MonthlySchedule +} + +func (*ScheduleCadence_Schedule_MonthlySchedule) isScheduleCadence_Schedule() {} + +// An immutable, point-in-time copy of a branch's data within a project. It +// remains available after the source branch is deleted.. +type Snapshot struct { + // The resource name of the snapshot. Format: + // projects/{project_id}/snapshots/{snapshot_id} + Name *string + // Unique system-generated ID for the snapshot. + Uid *string + // When the snapshot was created. + CreateTime *types.Time + // Client-provided configuration of the snapshot. + Spec *SnapshotSpec + // Server-observed state of the snapshot. + Status *SnapshotStatus + // The user-chosen ID; the final segment of `name`. + SnapshotId *string +} + +// Metadata for the long-running snapshot Create and Delete operations.. +type SnapshotOperationMetadata struct { +} + +// The automatic snapshot cadences for a branch. There is exactly one schedule +// per branch (singleton); it is configured in place, not created or deleted. +// +// Name: projects/{project_id}/branches/{branch_id}/snapshot-schedule. +type SnapshotSchedule struct { + // The resource name of the branch's snapshot schedule. Format: + // projects/{project_id}/branches/{branch_id}/snapshot-schedule + Name *string `fieldmask:"name"` + // The cadences at which automatic snapshots are taken. Update replaces the + // whole set; an empty set disables automatic snapshots. Order is not + // significant. When several cadences fire together, one snapshot is taken, + // retained for the longest of their retentions. + Schedule []ScheduleCadence `fieldmask:"schedule"` +} + +// Metadata for the long-running snapshot schedule Update operation.. +type SnapshotScheduleOperationMetadata struct { +} + +// Client-provided configuration of the snapshot.. +type SnapshotSpec struct { + // The source branch to snapshot. Format: + // projects/{project_id}/branches/{branch_id} + SourceBranch *string + // The point in time to snapshot from. If unset, the current head of the source + // branch is used. The chosen LSN or timestamp must fall within the project's + // point-in-time-recovery window (its history_retention_duration); otherwise the + // request returns INVALID_PARAMETER_VALUE. + PointInTime isSnapshotSpec_PointInTime + // Expiration policy. If unset, the snapshot is kept until deleted. + Expiration isSnapshotSpec_Expiration +} + +type isSnapshotSpec_PointInTime interface { + isSnapshotSpec_PointInTime() +} + +// SnapshotSpec_PointInTime_SourceBranchLsn selects SourceBranchLsn for SnapshotSpec.PointInTime. +// LSN to snapshot from, e.g. `16/B374D848`. Mutually exclusive with +// `source_branch_time`. +type SnapshotSpec_PointInTime_SourceBranchLsn struct { + SourceBranchLsn string +} + +func (*SnapshotSpec_PointInTime_SourceBranchLsn) isSnapshotSpec_PointInTime() {} + +// SnapshotSpec_PointInTime_SourceBranchTime selects SourceBranchTime for SnapshotSpec.PointInTime. +// Timestamp to snapshot from. Mutually exclusive with `source_branch_lsn`. +type SnapshotSpec_PointInTime_SourceBranchTime struct { + SourceBranchTime types.Time +} + +func (*SnapshotSpec_PointInTime_SourceBranchTime) isSnapshotSpec_PointInTime() {} + +type isSnapshotSpec_Expiration interface { + isSnapshotSpec_Expiration() +} + +// SnapshotSpec_Expiration_ExpireTime selects ExpireTime for SnapshotSpec.Expiration. +// Absolute time at which the snapshot is deleted. Mutually exclusive with `ttl` +// and `no_expiry`. +type SnapshotSpec_Expiration_ExpireTime struct { + ExpireTime types.Time +} + +func (*SnapshotSpec_Expiration_ExpireTime) isSnapshotSpec_Expiration() {} + +// SnapshotSpec_Expiration_Ttl selects Ttl for SnapshotSpec.Expiration. +// Time-to-live. The snapshot expires this long after it is created. Mutually +// exclusive with `expire_time` and `no_expiry`. Reads report the resolved +// absolute `expire_time` instead. +type SnapshotSpec_Expiration_Ttl struct { + Ttl types.Duration +} + +func (*SnapshotSpec_Expiration_Ttl) isSnapshotSpec_Expiration() {} + +// SnapshotSpec_Expiration_NoExpiry selects NoExpiry for SnapshotSpec.Expiration. +// If true, the snapshot never expires. Mutually exclusive with `ttl` and +// `expire_time`. +type SnapshotSpec_Expiration_NoExpiry struct { + NoExpiry bool +} + +func (*SnapshotSpec_Expiration_NoExpiry) isSnapshotSpec_Expiration() {} + +// Server-observed state of a snapshot.. +type SnapshotStatus struct { + // The source branch the snapshot was taken from. Format: + // projects/{project_id}/branches/{branch_id} + SourceBranch *string + // Observed expiration state of the snapshot. + Expiration isSnapshotStatus_Expiration + // Full logical size of the snapshot, in bytes. + FullSizeBytes *int64 + // Incremental storage size in bytes since the previous snapshot. Unset when the + // snapshot is not billed on incremental usage. + DiffSizeBytes *int64 +} + +type isSnapshotStatus_Expiration interface { + isSnapshotStatus_Expiration() +} + +// SnapshotStatus_Expiration_ExpireTime selects ExpireTime for SnapshotStatus.Expiration. +// Absolute time at which the snapshot is deleted. +type SnapshotStatus_Expiration_ExpireTime struct { + ExpireTime types.Time +} + +func (*SnapshotStatus_Expiration_ExpireTime) isSnapshotStatus_Expiration() {} + +// SnapshotStatus_Expiration_NoExpiry selects NoExpiry for SnapshotStatus.Expiration. +// True if the snapshot never expires. +type SnapshotStatus_Expiration_NoExpiry struct { + NoExpiry bool +} + +func (*SnapshotStatus_Expiration_NoExpiry) isSnapshotStatus_Expiration() {} + type SyncedTable struct { // Output only. The Full resource name of the synced table in Postgres where // (catalog, schema, table) are the UC entity names. @@ -2297,6 +2570,25 @@ type UpdateRoleRequest struct { UpdateMask *types.FieldMask[Role] } +// Request to set the snapshot schedule for a branch. Returns a completed +// long-running operation whose response is the persisted snapshot schedule.. +type UpdateSnapshotScheduleRequest struct { + // The snapshot schedule to set. Its `name` identifies the branch. Format: + // projects/{project_id}/branches/{branch_id}/snapshot-schedule + SnapshotSchedule *SnapshotSchedule + // Fields to update. The only updatable path is `schedule`, which replaces the + // entire set of cadences. + UpdateMask *types.FieldMask[SnapshotSchedule] +} + +// Take a snapshot once per week, on the configured day at the configured hour.. +type WeeklySchedule struct { + // The day of the week on which to take the snapshot. + DayOfWeek DayOfWeek + // The hour of the day, in UTC, at which to take the snapshot, in [0, 23]. + Hour *int +} + // Error returns the LRO error code and message. func (e *ApiError) Error() string { message := "unknown error" diff --git a/postgres/v1/wire.go b/postgres/v1/wire.go old mode 100755 new mode 100644 index f5f6c0d..564d54e --- a/postgres/v1/wire.go +++ b/postgres/v1/wire.go @@ -3,12 +3,57 @@ package postgres import ( + "bytes" "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + func fieldMaskToWire[T any](mask *types.FieldMask[T]) *string { if mask == nil { return nil @@ -113,6 +158,7 @@ type branchSpecWire struct { ExpireTime *types.Time `json:"expire_time,omitempty"` Ttl *types.Duration `json:"ttl,omitempty"` NoExpiry *bool `json:"no_expiry,omitempty"` + SourceSnapshot *string `json:"source_snapshot,omitempty"` } func branchSpecToWire(v *BranchSpec) (*branchSpecWire, error) { @@ -147,6 +193,7 @@ func branchSpecToWire(v *BranchSpec) (*branchSpecWire, error) { ExpireTime: expirationExpireTimeWire, Ttl: expirationTtlWire, NoExpiry: expirationNoExpiryWire, + SourceSnapshot: v.SourceSnapshot, }, nil } @@ -181,6 +228,7 @@ func branchSpecFromWire(w *branchSpecWire) (*BranchSpec, error) { SourceBranchLsn: w.SourceBranchLsn, SourceBranchTime: w.SourceBranchTime, IsProtected: w.IsProtected, + SourceSnapshot: w.SourceSnapshot, Expiration: expirationSelection, }, nil } @@ -194,17 +242,22 @@ type branchStatusWire struct { CurrentState BranchStatus_State `json:"current_state,omitempty"` PendingState BranchStatus_State `json:"pending_state,omitempty"` StateChangeTime *types.Time `json:"state_change_time,omitempty"` - LogicalSizeBytes *int64 `json:"logical_size_bytes,omitempty"` + LogicalSizeBytes *wireInt64 `json:"logical_size_bytes,omitempty"` ExpireTime *types.Time `json:"expire_time,omitempty"` BranchId *string `json:"branch_id,omitempty"` DeleteTime *types.Time `json:"delete_time,omitempty"` PurgeTime *types.Time `json:"purge_time,omitempty"` + SourceSnapshot *string `json:"source_snapshot,omitempty"` } func branchStatusToWire(v *BranchStatus) (*branchStatusWire, error) { if v == nil { return nil, nil } + logicalSizeBytesWireValue, err := int64ToWire(v.LogicalSizeBytes) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BranchStatus.LogicalSizeBytes", err) + } return &branchStatusWire{ SourceBranch: v.SourceBranch, SourceBranchLsn: v.SourceBranchLsn, @@ -214,11 +267,12 @@ func branchStatusToWire(v *BranchStatus) (*branchStatusWire, error) { CurrentState: v.CurrentState, PendingState: v.PendingState, StateChangeTime: v.StateChangeTime, - LogicalSizeBytes: v.LogicalSizeBytes, + LogicalSizeBytes: logicalSizeBytesWireValue, ExpireTime: v.ExpireTime, BranchId: v.BranchId, DeleteTime: v.DeleteTime, PurgeTime: v.PurgeTime, + SourceSnapshot: v.SourceSnapshot, }, nil } @@ -226,6 +280,10 @@ func branchStatusFromWire(w *branchStatusWire) (*BranchStatus, error) { if w == nil { return nil, nil } + logicalSizeBytesPublicValue, err := int64FromWire(w.LogicalSizeBytes) + if err != nil { + return nil, fmt.Errorf("%s: %w", "BranchStatus.LogicalSizeBytes", err) + } return &BranchStatus{ SourceBranch: w.SourceBranch, SourceBranchLsn: w.SourceBranchLsn, @@ -235,11 +293,12 @@ func branchStatusFromWire(w *branchStatusWire) (*BranchStatus, error) { CurrentState: w.CurrentState, PendingState: w.PendingState, StateChangeTime: w.StateChangeTime, - LogicalSizeBytes: w.LogicalSizeBytes, + LogicalSizeBytes: logicalSizeBytesPublicValue, ExpireTime: w.ExpireTime, BranchId: w.BranchId, DeleteTime: w.DeleteTime, PurgeTime: w.PurgeTime, + SourceSnapshot: w.SourceSnapshot, }, nil } @@ -609,6 +668,27 @@ func createRoleRequestToWire(v *CreateRoleRequest) (*createRoleRequestWire, erro }, nil } +type createSnapshotRequestWire struct { + Parent *string `json:"parent,omitempty"` + Snapshot *snapshotWire `json:"snapshot,omitempty"` + SnapshotId *string `json:"snapshot_id,omitempty"` +} + +func createSnapshotRequestToWire(v *CreateSnapshotRequest) (*createSnapshotRequestWire, error) { + if v == nil { + return nil, nil + } + snapshotWireValue, err := snapshotToWire(v.Snapshot) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateSnapshotRequest.Snapshot", err) + } + return &createSnapshotRequestWire{ + Parent: v.Parent, + Snapshot: snapshotWireValue, + SnapshotId: v.SnapshotId, + }, nil +} + type createSyncedTableRequestWire struct { SyncedTableId *string `json:"synced_table_id,omitempty"` SyncedTable *syncedTableWire `json:"synced_table,omitempty"` @@ -628,6 +708,28 @@ func createSyncedTableRequestToWire(v *CreateSyncedTableRequest) (*createSyncedT }, nil } +type dailyScheduleWire struct { + Hour *int `json:"hour,omitempty"` +} + +func dailyScheduleToWire(v *DailySchedule) (*dailyScheduleWire, error) { + if v == nil { + return nil, nil + } + return &dailyScheduleWire{ + Hour: v.Hour, + }, nil +} + +func dailyScheduleFromWire(w *dailyScheduleWire) (*DailySchedule, error) { + if w == nil { + return nil, nil + } + return &DailySchedule{ + Hour: w.Hour, + }, nil +} + type dataApiWire struct { Name *string `json:"name,omitempty"` Parent *string `json:"parent,omitempty"` @@ -984,7 +1086,7 @@ func deleteRoleRequestToWire(v *DeleteRoleRequest) (*deleteRoleRequestWire, erro } type deltaTableSyncInfoWire struct { - DeltaCommitVersion *int64 `json:"delta_commit_version,omitempty"` + DeltaCommitVersion *wireInt64 `json:"delta_commit_version,omitempty"` DeltaCommitTime *types.Time `json:"delta_commit_time,omitempty"` } @@ -992,8 +1094,12 @@ func deltaTableSyncInfoToWire(v *DeltaTableSyncInfo) (*deltaTableSyncInfoWire, e if v == nil { return nil, nil } + deltaCommitVersionWireValue, err := int64ToWire(v.DeltaCommitVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DeltaTableSyncInfo.DeltaCommitVersion", err) + } return &deltaTableSyncInfoWire{ - DeltaCommitVersion: v.DeltaCommitVersion, + DeltaCommitVersion: deltaCommitVersionWireValue, DeltaCommitTime: v.DeltaCommitTime, }, nil } @@ -1002,8 +1108,12 @@ func deltaTableSyncInfoFromWire(w *deltaTableSyncInfoWire) (*DeltaTableSyncInfo, if w == nil { return nil, nil } + deltaCommitVersionPublicValue, err := int64FromWire(w.DeltaCommitVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DeltaTableSyncInfo.DeltaCommitVersion", err) + } return &DeltaTableSyncInfo{ - DeltaCommitVersion: w.DeltaCommitVersion, + DeltaCommitVersion: deltaCommitVersionPublicValue, DeltaCommitTime: w.DeltaCommitTime, }, nil } @@ -1742,6 +1852,67 @@ func listRolesResponseFromWire(w *listRolesResponseWire) (*ListRolesResponse, er }, nil } +type listSnapshotsRequestWire struct { + Parent *string `json:"parent,omitempty"` + PageToken *string `json:"page_token,omitempty"` + PageSize *int `json:"page_size,omitempty"` +} + +func listSnapshotsRequestToWire(v *ListSnapshotsRequest) (*listSnapshotsRequestWire, error) { + if v == nil { + return nil, nil + } + return &listSnapshotsRequestWire{ + Parent: v.Parent, + PageToken: v.PageToken, + PageSize: v.PageSize, + }, nil +} + +type listSnapshotsResponseWire struct { + Snapshots []snapshotWire `json:"snapshots,omitempty"` + NextPageToken *string `json:"next_page_token,omitempty"` +} + +func listSnapshotsResponseFromWire(w *listSnapshotsResponseWire) (*ListSnapshotsResponse, error) { + if w == nil { + return nil, nil + } + snapshotsPublicValue, err := convertSlice(w.Snapshots, snapshotFromWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListSnapshotsResponse.Snapshots", err) + } + return &ListSnapshotsResponse{ + Snapshots: snapshotsPublicValue, + NextPageToken: w.NextPageToken, + }, nil +} + +type monthlyScheduleWire struct { + Day *int `json:"day,omitempty"` + Hour *int `json:"hour,omitempty"` +} + +func monthlyScheduleToWire(v *MonthlySchedule) (*monthlyScheduleWire, error) { + if v == nil { + return nil, nil + } + return &monthlyScheduleWire{ + Day: v.Day, + Hour: v.Hour, + }, nil +} + +func monthlyScheduleFromWire(w *monthlyScheduleWire) (*MonthlySchedule, error) { + if w == nil { + return nil, nil + } + return &MonthlySchedule{ + Day: w.Day, + Hour: w.Hour, + }, nil +} + type newPipelineSpecWire struct { StorageCatalog *string `json:"storage_catalog,omitempty"` StorageSchema *string `json:"storage_schema,omitempty"` @@ -2062,8 +2233,8 @@ type projectStatusWire struct { PgVersion *int `json:"pg_version,omitempty"` HistoryRetentionDuration *types.Duration `json:"history_retention_duration,omitempty"` DefaultEndpointSettings *projectDefaultEndpointSettingsWire `json:"default_endpoint_settings,omitempty"` - BranchLogicalSizeLimitBytes *int64 `json:"branch_logical_size_limit_bytes,omitempty"` - SyntheticStorageSizeBytes *int64 `json:"synthetic_storage_size_bytes,omitempty"` + BranchLogicalSizeLimitBytes *wireInt64 `json:"branch_logical_size_limit_bytes,omitempty"` + SyntheticStorageSizeBytes *wireInt64 `json:"synthetic_storage_size_bytes,omitempty"` ComputeLastActiveTime *types.Time `json:"compute_last_active_time,omitempty"` BudgetPolicyId *string `json:"budget_policy_id,omitempty"` CustomTags []projectCustomTagWire `json:"custom_tags,omitempty"` @@ -2081,6 +2252,14 @@ func projectStatusToWire(v *ProjectStatus) (*projectStatusWire, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "ProjectStatus.DefaultEndpointSettings", err) } + branchLogicalSizeLimitBytesWireValue, err := int64ToWire(v.BranchLogicalSizeLimitBytes) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ProjectStatus.BranchLogicalSizeLimitBytes", err) + } + syntheticStorageSizeBytesWireValue, err := int64ToWire(v.SyntheticStorageSizeBytes) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ProjectStatus.SyntheticStorageSizeBytes", err) + } customTagsWireValue, err := convertSlice(v.CustomTags, projectCustomTagToWire) if err != nil { return nil, fmt.Errorf("%s: %w", "ProjectStatus.CustomTags", err) @@ -2090,8 +2269,8 @@ func projectStatusToWire(v *ProjectStatus) (*projectStatusWire, error) { PgVersion: v.PgVersion, HistoryRetentionDuration: v.HistoryRetentionDuration, DefaultEndpointSettings: defaultEndpointSettingsWireValue, - BranchLogicalSizeLimitBytes: v.BranchLogicalSizeLimitBytes, - SyntheticStorageSizeBytes: v.SyntheticStorageSizeBytes, + BranchLogicalSizeLimitBytes: branchLogicalSizeLimitBytesWireValue, + SyntheticStorageSizeBytes: syntheticStorageSizeBytesWireValue, ComputeLastActiveTime: v.ComputeLastActiveTime, BudgetPolicyId: v.BudgetPolicyId, CustomTags: customTagsWireValue, @@ -2110,6 +2289,14 @@ func projectStatusFromWire(w *projectStatusWire) (*ProjectStatus, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "ProjectStatus.DefaultEndpointSettings", err) } + branchLogicalSizeLimitBytesPublicValue, err := int64FromWire(w.BranchLogicalSizeLimitBytes) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ProjectStatus.BranchLogicalSizeLimitBytes", err) + } + syntheticStorageSizeBytesPublicValue, err := int64FromWire(w.SyntheticStorageSizeBytes) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ProjectStatus.SyntheticStorageSizeBytes", err) + } customTagsPublicValue, err := convertSlice(w.CustomTags, projectCustomTagFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "ProjectStatus.CustomTags", err) @@ -2119,8 +2306,8 @@ func projectStatusFromWire(w *projectStatusWire) (*ProjectStatus, error) { PgVersion: w.PgVersion, HistoryRetentionDuration: w.HistoryRetentionDuration, DefaultEndpointSettings: defaultEndpointSettingsPublicValue, - BranchLogicalSizeLimitBytes: w.BranchLogicalSizeLimitBytes, - SyntheticStorageSizeBytes: w.SyntheticStorageSizeBytes, + BranchLogicalSizeLimitBytes: branchLogicalSizeLimitBytesPublicValue, + SyntheticStorageSizeBytes: syntheticStorageSizeBytesPublicValue, ComputeLastActiveTime: w.ComputeLastActiveTime, BudgetPolicyId: w.BudgetPolicyId, CustomTags: customTagsPublicValue, @@ -2354,6 +2541,396 @@ func roleOperationMetadataFromWire(w *roleOperationMetadataWire) (*RoleOperation return &RoleOperationMetadata{}, nil } +type scheduleCadenceWire struct { + DailySchedule *dailyScheduleWire `json:"daily_schedule,omitempty"` + WeeklySchedule *weeklyScheduleWire `json:"weekly_schedule,omitempty"` + MonthlySchedule *monthlyScheduleWire `json:"monthly_schedule,omitempty"` + Retention *types.Duration `json:"retention,omitempty"` +} + +func scheduleCadenceToWire(v *ScheduleCadence) (*scheduleCadenceWire, error) { + if v == nil { + return nil, nil + } + var scheduleDailyScheduleWire *dailyScheduleWire + var scheduleWeeklyScheduleWire *weeklyScheduleWire + var scheduleMonthlyScheduleWire *monthlyScheduleWire + switch value := v.Schedule.(type) { + case nil: + case *ScheduleCadence_Schedule_DailySchedule: + if value != nil { + scheduleDailyScheduleConverted, err := dailyScheduleToWire(&value.DailySchedule) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ScheduleCadence.Schedule.DailySchedule", err) + } + scheduleDailyScheduleWire = scheduleDailyScheduleConverted + } + case *ScheduleCadence_Schedule_WeeklySchedule: + if value != nil { + scheduleWeeklyScheduleConverted, err := weeklyScheduleToWire(&value.WeeklySchedule) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ScheduleCadence.Schedule.WeeklySchedule", err) + } + scheduleWeeklyScheduleWire = scheduleWeeklyScheduleConverted + } + case *ScheduleCadence_Schedule_MonthlySchedule: + if value != nil { + scheduleMonthlyScheduleConverted, err := monthlyScheduleToWire(&value.MonthlySchedule) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ScheduleCadence.Schedule.MonthlySchedule", err) + } + scheduleMonthlyScheduleWire = scheduleMonthlyScheduleConverted + } + default: + return nil, fmt.Errorf("%s: unsupported oneof implementation %T", "ScheduleCadence.Schedule", value) + } + return &scheduleCadenceWire{ + DailySchedule: scheduleDailyScheduleWire, + WeeklySchedule: scheduleWeeklyScheduleWire, + MonthlySchedule: scheduleMonthlyScheduleWire, + Retention: v.Retention, + }, nil +} + +func scheduleCadenceFromWire(w *scheduleCadenceWire) (*ScheduleCadence, error) { + if w == nil { + return nil, nil + } + scheduleMembers := 0 + if w.DailySchedule != nil { + scheduleMembers++ + } + if w.WeeklySchedule != nil { + scheduleMembers++ + } + if w.MonthlySchedule != nil { + scheduleMembers++ + } + if scheduleMembers > 1 { + return nil, fmt.Errorf("%s: multiple oneof members set", "ScheduleCadence.Schedule") + } + var scheduleSelection isScheduleCadence_Schedule + switch { + case w.DailySchedule != nil: + scheduleDailyScheduleConverted, err := dailyScheduleFromWire(w.DailySchedule) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ScheduleCadence.Schedule.DailySchedule", err) + } + scheduleSelection = &ScheduleCadence_Schedule_DailySchedule{DailySchedule: *scheduleDailyScheduleConverted} + case w.WeeklySchedule != nil: + scheduleWeeklyScheduleConverted, err := weeklyScheduleFromWire(w.WeeklySchedule) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ScheduleCadence.Schedule.WeeklySchedule", err) + } + scheduleSelection = &ScheduleCadence_Schedule_WeeklySchedule{WeeklySchedule: *scheduleWeeklyScheduleConverted} + case w.MonthlySchedule != nil: + scheduleMonthlyScheduleConverted, err := monthlyScheduleFromWire(w.MonthlySchedule) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ScheduleCadence.Schedule.MonthlySchedule", err) + } + scheduleSelection = &ScheduleCadence_Schedule_MonthlySchedule{MonthlySchedule: *scheduleMonthlyScheduleConverted} + } + return &ScheduleCadence{ + Retention: w.Retention, + Schedule: scheduleSelection, + }, nil +} + +type snapshotWire struct { + Name *string `json:"name,omitempty"` + Uid *string `json:"uid,omitempty"` + CreateTime *types.Time `json:"create_time,omitempty"` + Spec *snapshotSpecWire `json:"spec,omitempty"` + Status *snapshotStatusWire `json:"status,omitempty"` + SnapshotId *string `json:"snapshot_id,omitempty"` +} + +func snapshotToWire(v *Snapshot) (*snapshotWire, error) { + if v == nil { + return nil, nil + } + specWireValue, err := snapshotSpecToWire(v.Spec) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Snapshot.Spec", err) + } + statusWireValue, err := snapshotStatusToWire(v.Status) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Snapshot.Status", err) + } + return &snapshotWire{ + Name: v.Name, + Uid: v.Uid, + CreateTime: v.CreateTime, + Spec: specWireValue, + Status: statusWireValue, + SnapshotId: v.SnapshotId, + }, nil +} + +func snapshotFromWire(w *snapshotWire) (*Snapshot, error) { + if w == nil { + return nil, nil + } + specPublicValue, err := snapshotSpecFromWire(w.Spec) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Snapshot.Spec", err) + } + statusPublicValue, err := snapshotStatusFromWire(w.Status) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Snapshot.Status", err) + } + return &Snapshot{ + Name: w.Name, + Uid: w.Uid, + CreateTime: w.CreateTime, + Spec: specPublicValue, + Status: statusPublicValue, + SnapshotId: w.SnapshotId, + }, nil +} + +type snapshotOperationMetadataWire struct { +} + +func snapshotOperationMetadataFromWire(w *snapshotOperationMetadataWire) (*SnapshotOperationMetadata, error) { + if w == nil { + return nil, nil + } + return &SnapshotOperationMetadata{}, nil +} + +type snapshotScheduleWire struct { + Name *string `json:"name,omitempty"` + Schedule []scheduleCadenceWire `json:"schedule,omitempty"` +} + +func snapshotScheduleToWire(v *SnapshotSchedule) (*snapshotScheduleWire, error) { + if v == nil { + return nil, nil + } + scheduleWireValue, err := convertSlice(v.Schedule, scheduleCadenceToWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SnapshotSchedule.Schedule", err) + } + return &snapshotScheduleWire{ + Name: v.Name, + Schedule: scheduleWireValue, + }, nil +} + +func snapshotScheduleFromWire(w *snapshotScheduleWire) (*SnapshotSchedule, error) { + if w == nil { + return nil, nil + } + schedulePublicValue, err := convertSlice(w.Schedule, scheduleCadenceFromWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SnapshotSchedule.Schedule", err) + } + return &SnapshotSchedule{ + Name: w.Name, + Schedule: schedulePublicValue, + }, nil +} + +type snapshotScheduleOperationMetadataWire struct { +} + +func snapshotScheduleOperationMetadataFromWire(w *snapshotScheduleOperationMetadataWire) (*SnapshotScheduleOperationMetadata, error) { + if w == nil { + return nil, nil + } + return &SnapshotScheduleOperationMetadata{}, nil +} + +type snapshotSpecWire struct { + SourceBranch *string `json:"source_branch,omitempty"` + SourceBranchLsn *string `json:"source_branch_lsn,omitempty"` + SourceBranchTime *types.Time `json:"source_branch_time,omitempty"` + ExpireTime *types.Time `json:"expire_time,omitempty"` + Ttl *types.Duration `json:"ttl,omitempty"` + NoExpiry *bool `json:"no_expiry,omitempty"` +} + +func snapshotSpecToWire(v *SnapshotSpec) (*snapshotSpecWire, error) { + if v == nil { + return nil, nil + } + var pointInTimeSourceBranchLsnWire *string + var pointInTimeSourceBranchTimeWire *types.Time + switch value := v.PointInTime.(type) { + case nil: + case *SnapshotSpec_PointInTime_SourceBranchLsn: + if value != nil { + pointInTimeSourceBranchLsnWire = new(value.SourceBranchLsn) + } + case *SnapshotSpec_PointInTime_SourceBranchTime: + if value != nil { + pointInTimeSourceBranchTimeWire = new(value.SourceBranchTime) + } + default: + return nil, fmt.Errorf("%s: unsupported oneof implementation %T", "SnapshotSpec.PointInTime", value) + } + var expirationExpireTimeWire *types.Time + var expirationTtlWire *types.Duration + var expirationNoExpiryWire *bool + switch value := v.Expiration.(type) { + case nil: + case *SnapshotSpec_Expiration_ExpireTime: + if value != nil { + expirationExpireTimeWire = new(value.ExpireTime) + } + case *SnapshotSpec_Expiration_Ttl: + if value != nil { + expirationTtlWire = new(value.Ttl) + } + case *SnapshotSpec_Expiration_NoExpiry: + if value != nil { + expirationNoExpiryWire = new(value.NoExpiry) + } + default: + return nil, fmt.Errorf("%s: unsupported oneof implementation %T", "SnapshotSpec.Expiration", value) + } + return &snapshotSpecWire{ + SourceBranch: v.SourceBranch, + SourceBranchLsn: pointInTimeSourceBranchLsnWire, + SourceBranchTime: pointInTimeSourceBranchTimeWire, + ExpireTime: expirationExpireTimeWire, + Ttl: expirationTtlWire, + NoExpiry: expirationNoExpiryWire, + }, nil +} + +func snapshotSpecFromWire(w *snapshotSpecWire) (*SnapshotSpec, error) { + if w == nil { + return nil, nil + } + pointInTimeMembers := 0 + if w.SourceBranchLsn != nil { + pointInTimeMembers++ + } + if w.SourceBranchTime != nil { + pointInTimeMembers++ + } + if pointInTimeMembers > 1 { + return nil, fmt.Errorf("%s: multiple oneof members set", "SnapshotSpec.PointInTime") + } + expirationMembers := 0 + if w.ExpireTime != nil { + expirationMembers++ + } + if w.Ttl != nil { + expirationMembers++ + } + if w.NoExpiry != nil { + expirationMembers++ + } + if expirationMembers > 1 { + return nil, fmt.Errorf("%s: multiple oneof members set", "SnapshotSpec.Expiration") + } + var pointInTimeSelection isSnapshotSpec_PointInTime + switch { + case w.SourceBranchLsn != nil: + pointInTimeSelection = &SnapshotSpec_PointInTime_SourceBranchLsn{SourceBranchLsn: *w.SourceBranchLsn} + case w.SourceBranchTime != nil: + pointInTimeSelection = &SnapshotSpec_PointInTime_SourceBranchTime{SourceBranchTime: *w.SourceBranchTime} + } + var expirationSelection isSnapshotSpec_Expiration + switch { + case w.ExpireTime != nil: + expirationSelection = &SnapshotSpec_Expiration_ExpireTime{ExpireTime: *w.ExpireTime} + case w.Ttl != nil: + expirationSelection = &SnapshotSpec_Expiration_Ttl{Ttl: *w.Ttl} + case w.NoExpiry != nil: + expirationSelection = &SnapshotSpec_Expiration_NoExpiry{NoExpiry: *w.NoExpiry} + } + return &SnapshotSpec{ + SourceBranch: w.SourceBranch, + PointInTime: pointInTimeSelection, + Expiration: expirationSelection, + }, nil +} + +type snapshotStatusWire struct { + SourceBranch *string `json:"source_branch,omitempty"` + ExpireTime *types.Time `json:"expire_time,omitempty"` + NoExpiry *bool `json:"no_expiry,omitempty"` + FullSizeBytes *wireInt64 `json:"full_size_bytes,omitempty"` + DiffSizeBytes *wireInt64 `json:"diff_size_bytes,omitempty"` +} + +func snapshotStatusToWire(v *SnapshotStatus) (*snapshotStatusWire, error) { + if v == nil { + return nil, nil + } + fullSizeBytesWireValue, err := int64ToWire(v.FullSizeBytes) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SnapshotStatus.FullSizeBytes", err) + } + diffSizeBytesWireValue, err := int64ToWire(v.DiffSizeBytes) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SnapshotStatus.DiffSizeBytes", err) + } + var expirationExpireTimeWire *types.Time + var expirationNoExpiryWire *bool + switch value := v.Expiration.(type) { + case nil: + case *SnapshotStatus_Expiration_ExpireTime: + if value != nil { + expirationExpireTimeWire = new(value.ExpireTime) + } + case *SnapshotStatus_Expiration_NoExpiry: + if value != nil { + expirationNoExpiryWire = new(value.NoExpiry) + } + default: + return nil, fmt.Errorf("%s: unsupported oneof implementation %T", "SnapshotStatus.Expiration", value) + } + return &snapshotStatusWire{ + SourceBranch: v.SourceBranch, + ExpireTime: expirationExpireTimeWire, + NoExpiry: expirationNoExpiryWire, + FullSizeBytes: fullSizeBytesWireValue, + DiffSizeBytes: diffSizeBytesWireValue, + }, nil +} + +func snapshotStatusFromWire(w *snapshotStatusWire) (*SnapshotStatus, error) { + if w == nil { + return nil, nil + } + expirationMembers := 0 + if w.ExpireTime != nil { + expirationMembers++ + } + if w.NoExpiry != nil { + expirationMembers++ + } + if expirationMembers > 1 { + return nil, fmt.Errorf("%s: multiple oneof members set", "SnapshotStatus.Expiration") + } + fullSizeBytesPublicValue, err := int64FromWire(w.FullSizeBytes) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SnapshotStatus.FullSizeBytes", err) + } + diffSizeBytesPublicValue, err := int64FromWire(w.DiffSizeBytes) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SnapshotStatus.DiffSizeBytes", err) + } + var expirationSelection isSnapshotStatus_Expiration + switch { + case w.ExpireTime != nil: + expirationSelection = &SnapshotStatus_Expiration_ExpireTime{ExpireTime: *w.ExpireTime} + case w.NoExpiry != nil: + expirationSelection = &SnapshotStatus_Expiration_NoExpiry{NoExpiry: *w.NoExpiry} + } + return &SnapshotStatus{ + SourceBranch: w.SourceBranch, + FullSizeBytes: fullSizeBytesPublicValue, + DiffSizeBytes: diffSizeBytesPublicValue, + Expiration: expirationSelection, + }, nil +} + type syncedTableWire struct { Name *string `json:"name,omitempty"` Uid *string `json:"uid,omitempty"` @@ -2551,7 +3128,7 @@ type syncedTable_SyncedTableStatusWire struct { LastSync *syncedTablePositionWire `json:"last_sync,omitempty"` OngoingSyncProgress *syncedTablePipelineProgressWire `json:"ongoing_sync_progress,omitempty"` ProvisioningPhase ProvisioningPhase `json:"provisioning_phase,omitempty"` - LastProcessedCommitVersion *int64 `json:"last_processed_commit_version,omitempty"` + LastProcessedCommitVersion *wireInt64 `json:"last_processed_commit_version,omitempty"` LastSyncTime *types.Time `json:"last_sync_time,omitempty"` PipelineId *string `json:"pipeline_id,omitempty"` UnityCatalogProvisioningState ProvisioningInfo_State `json:"unity_catalog_provisioning_state,omitempty"` @@ -2570,13 +3147,17 @@ func syncedTable_SyncedTableStatusToWire(v *SyncedTable_SyncedTableStatus) (*syn if err != nil { return nil, fmt.Errorf("%s: %w", "SyncedTable_SyncedTableStatus.OngoingSyncProgress", err) } + lastProcessedCommitVersionWireValue, err := int64ToWire(v.LastProcessedCommitVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTable_SyncedTableStatus.LastProcessedCommitVersion", err) + } return &syncedTable_SyncedTableStatusWire{ Message: v.Message, DetailedState: v.DetailedState, LastSync: lastSyncWireValue, OngoingSyncProgress: ongoingSyncProgressWireValue, ProvisioningPhase: v.ProvisioningPhase, - LastProcessedCommitVersion: v.LastProcessedCommitVersion, + LastProcessedCommitVersion: lastProcessedCommitVersionWireValue, LastSyncTime: v.LastSyncTime, PipelineId: v.PipelineId, UnityCatalogProvisioningState: v.UnityCatalogProvisioningState, @@ -2596,13 +3177,17 @@ func syncedTable_SyncedTableStatusFromWire(w *syncedTable_SyncedTableStatusWire) if err != nil { return nil, fmt.Errorf("%s: %w", "SyncedTable_SyncedTableStatus.OngoingSyncProgress", err) } + lastProcessedCommitVersionPublicValue, err := int64FromWire(w.LastProcessedCommitVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTable_SyncedTableStatus.LastProcessedCommitVersion", err) + } return &SyncedTable_SyncedTableStatus{ Message: w.Message, DetailedState: w.DetailedState, LastSync: lastSyncPublicValue, OngoingSyncProgress: ongoingSyncProgressPublicValue, ProvisioningPhase: w.ProvisioningPhase, - LastProcessedCommitVersion: w.LastProcessedCommitVersion, + LastProcessedCommitVersion: lastProcessedCommitVersionPublicValue, LastSyncTime: w.LastSyncTime, PipelineId: w.PipelineId, UnityCatalogProvisioningState: w.UnityCatalogProvisioningState, @@ -2621,21 +3206,33 @@ func syncedTableOperationMetadataFromWire(w *syncedTableOperationMetadataWire) ( } type syncedTablePipelineProgressWire struct { - LatestVersionCurrentlyProcessing *int64 `json:"latest_version_currently_processing,omitempty"` - SyncedRowCount *int64 `json:"synced_row_count,omitempty"` - TotalRowCount *int64 `json:"total_row_count,omitempty"` - SyncProgressCompletion *float64 `json:"sync_progress_completion,omitempty"` - EstimatedCompletionTimeSeconds *float64 `json:"estimated_completion_time_seconds,omitempty"` + LatestVersionCurrentlyProcessing *wireInt64 `json:"latest_version_currently_processing,omitempty"` + SyncedRowCount *wireInt64 `json:"synced_row_count,omitempty"` + TotalRowCount *wireInt64 `json:"total_row_count,omitempty"` + SyncProgressCompletion *float64 `json:"sync_progress_completion,omitempty"` + EstimatedCompletionTimeSeconds *float64 `json:"estimated_completion_time_seconds,omitempty"` } func syncedTablePipelineProgressToWire(v *SyncedTablePipelineProgress) (*syncedTablePipelineProgressWire, error) { if v == nil { return nil, nil } + latestVersionCurrentlyProcessingWireValue, err := int64ToWire(v.LatestVersionCurrentlyProcessing) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTablePipelineProgress.LatestVersionCurrentlyProcessing", err) + } + syncedRowCountWireValue, err := int64ToWire(v.SyncedRowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTablePipelineProgress.SyncedRowCount", err) + } + totalRowCountWireValue, err := int64ToWire(v.TotalRowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTablePipelineProgress.TotalRowCount", err) + } return &syncedTablePipelineProgressWire{ - LatestVersionCurrentlyProcessing: v.LatestVersionCurrentlyProcessing, - SyncedRowCount: v.SyncedRowCount, - TotalRowCount: v.TotalRowCount, + LatestVersionCurrentlyProcessing: latestVersionCurrentlyProcessingWireValue, + SyncedRowCount: syncedRowCountWireValue, + TotalRowCount: totalRowCountWireValue, SyncProgressCompletion: v.SyncProgressCompletion, EstimatedCompletionTimeSeconds: v.EstimatedCompletionTimeSeconds, }, nil @@ -2645,10 +3242,22 @@ func syncedTablePipelineProgressFromWire(w *syncedTablePipelineProgressWire) (*S if w == nil { return nil, nil } + latestVersionCurrentlyProcessingPublicValue, err := int64FromWire(w.LatestVersionCurrentlyProcessing) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTablePipelineProgress.LatestVersionCurrentlyProcessing", err) + } + syncedRowCountPublicValue, err := int64FromWire(w.SyncedRowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTablePipelineProgress.SyncedRowCount", err) + } + totalRowCountPublicValue, err := int64FromWire(w.TotalRowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SyncedTablePipelineProgress.TotalRowCount", err) + } return &SyncedTablePipelineProgress{ - LatestVersionCurrentlyProcessing: w.LatestVersionCurrentlyProcessing, - SyncedRowCount: w.SyncedRowCount, - TotalRowCount: w.TotalRowCount, + LatestVersionCurrentlyProcessing: latestVersionCurrentlyProcessingPublicValue, + SyncedRowCount: syncedRowCountPublicValue, + TotalRowCount: totalRowCountPublicValue, SyncProgressCompletion: w.SyncProgressCompletion, EstimatedCompletionTimeSeconds: w.EstimatedCompletionTimeSeconds, }, nil @@ -2852,6 +3461,50 @@ func updateRoleRequestToWire(v *UpdateRoleRequest) (*updateRoleRequestWire, erro }, nil } +type updateSnapshotScheduleRequestWire struct { + SnapshotSchedule *snapshotScheduleWire `json:"snapshot_schedule,omitempty"` + UpdateMask *string `json:"update_mask,omitempty"` +} + +func updateSnapshotScheduleRequestToWire(v *UpdateSnapshotScheduleRequest) (*updateSnapshotScheduleRequestWire, error) { + if v == nil { + return nil, nil + } + snapshotScheduleWireValue, err := snapshotScheduleToWire(v.SnapshotSchedule) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateSnapshotScheduleRequest.SnapshotSchedule", err) + } + return &updateSnapshotScheduleRequestWire{ + SnapshotSchedule: snapshotScheduleWireValue, + UpdateMask: fieldMaskToWire(v.UpdateMask), + }, nil +} + +type weeklyScheduleWire struct { + DayOfWeek DayOfWeek `json:"day_of_week,omitempty"` + Hour *int `json:"hour,omitempty"` +} + +func weeklyScheduleToWire(v *WeeklySchedule) (*weeklyScheduleWire, error) { + if v == nil { + return nil, nil + } + return &weeklyScheduleWire{ + DayOfWeek: v.DayOfWeek, + Hour: v.Hour, + }, nil +} + +func weeklyScheduleFromWire(w *weeklyScheduleWire) (*WeeklySchedule, error) { + if w == nil { + return nil, nil + } + return &WeeklySchedule{ + DayOfWeek: w.DayOfWeek, + Hour: w.Hour, + }, nil +} + func convertSlice[T, W any](s []T, conv func(*T) (*W, error)) ([]W, error) { if s == nil { return nil, nil diff --git a/queries/CHANGELOG.md b/queries/CHANGELOG.md index 6224c04..19f237c 100644 --- a/queries/CHANGELOG.md +++ b/queries/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/queries/go.mod b/queries/go.mod index d6882c6..f5617d0 100644 --- a/queries/go.mod +++ b/queries/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/queries/internal/version.go b/queries/internal/version.go index 73e2776..378a26a 100644 --- a/queries/internal/version.go +++ b/queries/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-queries" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/queries/v1/client.go b/queries/v1/client.go old mode 100755 new mode 100644 index 3430c0f..0079743 --- a/queries/v1/client.go +++ b/queries/v1/client.go @@ -75,8 +75,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Creates a query. -func (c *internalClient) CreateQuery(ctx context.Context, req *CreateQueryRequest, opts ...call.Option) (*Query, error) { - wireReq, err := createQueryRequestToWire(req) +func (c *internalClient) CreateQuery(ctx context.Context, req CreateQueryRequest, opts ...call.Option) (*Query, error) { + wireReq, err := createQueryRequestToWire(&req) if err != nil { return nil, err } @@ -141,7 +141,7 @@ func (c *internalClient) CreateQuery(ctx context.Context, req *CreateQueryReques } // Gets a query. -func (c *internalClient) GetQuery(ctx context.Context, req *GetQueryRequest, opts ...call.Option) (*Query, error) { +func (c *internalClient) GetQuery(ctx context.Context, req GetQueryRequest, opts ...call.Option) (*Query, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -155,7 +155,11 @@ func (c *internalClient) GetQuery(ctx context.Context, req *GetQueryRequest, opt } pb := pathBuilder{} pb.literal("/api/2.0/sql/queries/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -203,8 +207,8 @@ func (c *internalClient) GetQuery(ctx context.Context, req *GetQueryRequest, opt // Gets a list of queries accessible to the user, ordered by creation time. // **Warning:** Calling this API concurrently 10 or more times could result in // throttling, service degradation, or a temporary ban. -func (c *internalClient) ListQueries(ctx context.Context, req *ListQueriesRequest, opts ...call.Option) (*ListQueriesResponse, error) { - wireReq, err := listQueriesRequestToWire(req) +func (c *internalClient) ListQueries(ctx context.Context, req ListQueriesRequest, opts ...call.Option) (*ListQueriesResponse, error) { + wireReq, err := listQueriesRequestToWire(&req) if err != nil { return nil, err } @@ -274,7 +278,7 @@ func (c *internalClient) ListQueries(ctx context.Context, req *ListQueriesReques // // For example: // -// for item, err := range c.ListQueriesIter(ctx, &ListQueriesRequest{}) { +// for item, err := range c.ListQueriesIter(ctx, ListQueriesRequest{}) { // if err != nil { // return err // } @@ -286,16 +290,13 @@ func (c *internalClient) ListQueries(ctx context.Context, req *ListQueriesReques // // Callers who need custom pagination logic should use // ListQueries directly. -func (c *internalClient) ListQueriesIter(ctx context.Context, req *ListQueriesRequest, opts ...call.Option) iter.Seq2[*ListQueryObjectsResponseQuery, error] { +func (c *internalClient) ListQueriesIter(ctx context.Context, req ListQueriesRequest, opts ...call.Option) iter.Seq2[*ListQueryObjectsResponseQuery, error] { return func(yield func(*ListQueryObjectsResponseQuery, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListQueriesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListQueries(ctx, &pageReq, opts...) + resp, err := c.ListQueries(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -314,8 +315,8 @@ func (c *internalClient) ListQueriesIter(ctx context.Context, req *ListQueriesRe } // Gets a list of visualizations on a query. -func (c *internalClient) ListVisualizationsForQuery(ctx context.Context, req *ListVisualizationsForQueryRequest, opts ...call.Option) (*ListVisualizationsForQueryResponse, error) { - wireReq, err := listVisualizationsForQueryRequestToWire(req) +func (c *internalClient) ListVisualizationsForQuery(ctx context.Context, req ListVisualizationsForQueryRequest, opts ...call.Option) (*ListVisualizationsForQueryResponse, error) { + wireReq, err := listVisualizationsForQueryRequestToWire(&req) if err != nil { return nil, err } @@ -332,7 +333,11 @@ func (c *internalClient) ListVisualizationsForQuery(ctx context.Context, req *Li } pb := pathBuilder{} pb.literal("/api/2.0/sql/queries/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } pb.literal("/visualizations") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -389,7 +394,7 @@ func (c *internalClient) ListVisualizationsForQuery(ctx context.Context, req *Li // // For example: // -// for item, err := range c.ListVisualizationsForQueryIter(ctx, &ListVisualizationsForQueryRequest{}) { +// for item, err := range c.ListVisualizationsForQueryIter(ctx, ListVisualizationsForQueryRequest{}) { // if err != nil { // return err // } @@ -401,16 +406,13 @@ func (c *internalClient) ListVisualizationsForQuery(ctx context.Context, req *Li // // Callers who need custom pagination logic should use // ListVisualizationsForQuery directly. -func (c *internalClient) ListVisualizationsForQueryIter(ctx context.Context, req *ListVisualizationsForQueryRequest, opts ...call.Option) iter.Seq2[*Visualization, error] { +func (c *internalClient) ListVisualizationsForQueryIter(ctx context.Context, req ListVisualizationsForQueryRequest, opts ...call.Option) iter.Seq2[*Visualization, error] { return func(yield func(*Visualization, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListVisualizationsForQueryRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListVisualizationsForQuery(ctx, &pageReq, opts...) + resp, err := c.ListVisualizationsForQuery(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -432,7 +434,7 @@ func (c *internalClient) ListVisualizationsForQueryIter(ctx context.Context, req // searches and list views, and cannot be used for alerts. You can restore a // trashed query through the UI. A trashed query is permanently deleted after 30 // days. -func (c *internalClient) TrashQuery(ctx context.Context, req *TrashQueryRequest, opts ...call.Option) (*Empty, error) { +func (c *internalClient) TrashQuery(ctx context.Context, req TrashQueryRequest, opts ...call.Option) (*Empty, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -446,7 +448,11 @@ func (c *internalClient) TrashQuery(ctx context.Context, req *TrashQueryRequest, } pb := pathBuilder{} pb.literal("/api/2.0/sql/queries/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -486,8 +492,8 @@ func (c *internalClient) TrashQuery(ctx context.Context, req *TrashQueryRequest, } // Updates a query. -func (c *internalClient) UpdateQuery(ctx context.Context, req *UpdateQueryRequest, opts ...call.Option) (*Query, error) { - wireReq, err := updateQueryRequestToWire(req) +func (c *internalClient) UpdateQuery(ctx context.Context, req UpdateQueryRequest, opts ...call.Option) (*Query, error) { + wireReq, err := updateQueryRequestToWire(&req) if err != nil { return nil, err } @@ -508,7 +514,11 @@ func (c *internalClient) UpdateQuery(ctx context.Context, req *UpdateQueryReques } pb := pathBuilder{} pb.literal("/api/2.0/sql/queries/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/queries/v1/genhelper.go b/queries/v1/genhelper.go old mode 100755 new mode 100644 index cc64b69..7120a7b --- a/queries/v1/genhelper.go +++ b/queries/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/queryhistory/CHANGELOG.md b/queryhistory/CHANGELOG.md index 6224c04..19f237c 100644 --- a/queryhistory/CHANGELOG.md +++ b/queryhistory/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/queryhistory/go.mod b/queryhistory/go.mod index 9e2167f..38d3611 100644 --- a/queryhistory/go.mod +++ b/queryhistory/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/queryhistory/internal/version.go b/queryhistory/internal/version.go index 77e6a94..b4a0fca 100644 --- a/queryhistory/internal/version.go +++ b/queryhistory/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-queryhistory" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/queryhistory/v1/client.go b/queryhistory/v1/client.go old mode 100755 new mode 100644 index 2045f0c..5efa0bc --- a/queryhistory/v1/client.go +++ b/queryhistory/v1/client.go @@ -78,8 +78,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // recently started queries are returned first (up to max_results in request). // The pagination token returned in response can be used to list subsequent // query statuses. -func (c *internalClient) ListQueries(ctx context.Context, req *ListQueriesRequest, opts ...call.Option) (*ListQueriesResponse, error) { - wireReq, err := listQueriesRequestToWire(req) +func (c *internalClient) ListQueries(ctx context.Context, req ListQueriesRequest, opts ...call.Option) (*ListQueriesResponse, error) { + wireReq, err := listQueriesRequestToWire(&req) if err != nil { return nil, err } diff --git a/queryhistory/v1/wire.go b/queryhistory/v1/wire.go old mode 100755 new mode 100644 index f1369fa..3538880 --- a/queryhistory/v1/wire.go +++ b/queryhistory/v1/wire.go @@ -3,9 +3,55 @@ package queryhistory import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type channelInfoWire struct { Name ChannelName `json:"name,omitempty"` DbsqlVersion *string `json:"dbsql_version,omitempty"` @@ -113,7 +159,7 @@ func listQueriesResponseFromWire(w *listQueriesResponseWire) (*ListQueriesRespon type queryFilterWire struct { QueryStartTimeRange *timeRangeWire `json:"query_start_time_range,omitempty"` - UserIds []int64 `json:"user_ids,omitempty"` + UserIds []wireInt64 `json:"user_ids,omitempty"` Statuses []QueryStatus `json:"statuses,omitempty"` WarehouseIds []string `json:"warehouse_ids,omitempty"` StatementIds []string `json:"statement_ids,omitempty"` @@ -127,9 +173,13 @@ func queryFilterToWire(v *QueryFilter) (*queryFilterWire, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "QueryFilter.QueryStartTimeRange", err) } + userIdsWireValue, err := convertSlice(v.UserIds, int64ToWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryFilter.UserIds", err) + } return &queryFilterWire{ QueryStartTimeRange: queryStartTimeRangeWireValue, - UserIds: v.UserIds, + UserIds: userIdsWireValue, Statuses: v.Statuses, WarehouseIds: v.WarehouseIds, StatementIds: v.StatementIds, @@ -140,18 +190,18 @@ type queryInfoWire struct { QueryId *string `json:"query_id,omitempty"` Status QueryStatus `json:"status,omitempty"` QueryText *string `json:"query_text,omitempty"` - QueryStartTimeMs *int64 `json:"query_start_time_ms,omitempty"` - ExecutionEndTimeMs *int64 `json:"execution_end_time_ms,omitempty"` - QueryEndTimeMs *int64 `json:"query_end_time_ms,omitempty"` - UserId *int64 `json:"user_id,omitempty"` + QueryStartTimeMs *wireInt64 `json:"query_start_time_ms,omitempty"` + ExecutionEndTimeMs *wireInt64 `json:"execution_end_time_ms,omitempty"` + QueryEndTimeMs *wireInt64 `json:"query_end_time_ms,omitempty"` + UserId *wireInt64 `json:"user_id,omitempty"` UserName *string `json:"user_name,omitempty"` SparkUiUrl *string `json:"spark_ui_url,omitempty"` EndpointId *string `json:"endpoint_id,omitempty"` - RowsProduced *int64 `json:"rows_produced,omitempty"` + RowsProduced *wireInt64 `json:"rows_produced,omitempty"` ErrorMessage *string `json:"error_message,omitempty"` LookupKey *string `json:"lookup_key,omitempty"` Metrics *queryMetricsWire `json:"metrics,omitempty"` - ExecutedAsUserId *int64 `json:"executed_as_user_id,omitempty"` + ExecutedAsUserId *wireInt64 `json:"executed_as_user_id,omitempty"` ExecutedAsUserName *string `json:"executed_as_user_name,omitempty"` SessionId *string `json:"session_id,omitempty"` IsFinal *bool `json:"is_final,omitempty"` @@ -159,7 +209,7 @@ type queryInfoWire struct { PlansState PlansState `json:"plans_state,omitempty"` StatementType QueryStatementType `json:"statement_type,omitempty"` WarehouseId *string `json:"warehouse_id,omitempty"` - Duration *int64 `json:"duration,omitempty"` + Duration *wireInt64 `json:"duration,omitempty"` ClientApplication *string `json:"client_application,omitempty"` QuerySource *externalQuerySourceWire `json:"query_source,omitempty"` CacheQueryId *string `json:"cache_query_id,omitempty"` @@ -170,14 +220,42 @@ func queryInfoFromWire(w *queryInfoWire) (*QueryInfo, error) { if w == nil { return nil, nil } + queryStartTimeMsPublicValue, err := int64FromWire(w.QueryStartTimeMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryInfo.QueryStartTimeMs", err) + } + executionEndTimeMsPublicValue, err := int64FromWire(w.ExecutionEndTimeMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryInfo.ExecutionEndTimeMs", err) + } + queryEndTimeMsPublicValue, err := int64FromWire(w.QueryEndTimeMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryInfo.QueryEndTimeMs", err) + } + userIdPublicValue, err := int64FromWire(w.UserId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryInfo.UserId", err) + } + rowsProducedPublicValue, err := int64FromWire(w.RowsProduced) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryInfo.RowsProduced", err) + } metricsPublicValue, err := queryMetricsFromWire(w.Metrics) if err != nil { return nil, fmt.Errorf("%s: %w", "QueryInfo.Metrics", err) } + executedAsUserIdPublicValue, err := int64FromWire(w.ExecutedAsUserId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryInfo.ExecutedAsUserId", err) + } channelUsedPublicValue, err := channelInfoFromWire(w.ChannelUsed) if err != nil { return nil, fmt.Errorf("%s: %w", "QueryInfo.ChannelUsed", err) } + durationPublicValue, err := int64FromWire(w.Duration) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryInfo.Duration", err) + } querySourcePublicValue, err := externalQuerySourceFromWire(w.QuerySource) if err != nil { return nil, fmt.Errorf("%s: %w", "QueryInfo.QuerySource", err) @@ -190,18 +268,18 @@ func queryInfoFromWire(w *queryInfoWire) (*QueryInfo, error) { QueryId: w.QueryId, Status: w.Status, QueryText: w.QueryText, - QueryStartTimeMs: w.QueryStartTimeMs, - ExecutionEndTimeMs: w.ExecutionEndTimeMs, - QueryEndTimeMs: w.QueryEndTimeMs, - UserId: w.UserId, + QueryStartTimeMs: queryStartTimeMsPublicValue, + ExecutionEndTimeMs: executionEndTimeMsPublicValue, + QueryEndTimeMs: queryEndTimeMsPublicValue, + UserId: userIdPublicValue, UserName: w.UserName, SparkUiUrl: w.SparkUiUrl, EndpointId: w.EndpointId, - RowsProduced: w.RowsProduced, + RowsProduced: rowsProducedPublicValue, ErrorMessage: w.ErrorMessage, LookupKey: w.LookupKey, Metrics: metricsPublicValue, - ExecutedAsUserId: w.ExecutedAsUserId, + ExecutedAsUserId: executedAsUserIdPublicValue, ExecutedAsUserName: w.ExecutedAsUserName, SessionId: w.SessionId, IsFinal: w.IsFinal, @@ -209,7 +287,7 @@ func queryInfoFromWire(w *queryInfoWire) (*QueryInfo, error) { PlansState: w.PlansState, StatementType: w.StatementType, WarehouseId: w.WarehouseId, - Duration: w.Duration, + Duration: durationPublicValue, ClientApplication: w.ClientApplication, QuerySource: querySourcePublicValue, CacheQueryId: w.CacheQueryId, @@ -218,75 +296,183 @@ func queryInfoFromWire(w *queryInfoWire) (*QueryInfo, error) { } type queryMetricsWire struct { - TotalTimeMs *int64 `json:"total_time_ms,omitempty"` - ReadBytes *int64 `json:"read_bytes,omitempty"` - RowsProducedCount *int64 `json:"rows_produced_count,omitempty"` - CompilationTimeMs *int64 `json:"compilation_time_ms,omitempty"` - ExecutionTimeMs *int64 `json:"execution_time_ms,omitempty"` - ReadRemoteBytes *int64 `json:"read_remote_bytes,omitempty"` - WriteRemoteBytes *int64 `json:"write_remote_bytes,omitempty"` - ReadCacheBytes *int64 `json:"read_cache_bytes,omitempty"` - SpillToDiskBytes *int64 `json:"spill_to_disk_bytes,omitempty"` - TaskTotalTimeMs *int64 `json:"task_total_time_ms,omitempty"` - ReadFilesCount *int64 `json:"read_files_count,omitempty"` - ReadPartitionsCount *int64 `json:"read_partitions_count,omitempty"` - PhotonTotalTimeMs *int64 `json:"photon_total_time_ms,omitempty"` - RowsReadCount *int64 `json:"rows_read_count,omitempty"` - ResultFetchTimeMs *int64 `json:"result_fetch_time_ms,omitempty"` - NetworkSentBytes *int64 `json:"network_sent_bytes,omitempty"` + TotalTimeMs *wireInt64 `json:"total_time_ms,omitempty"` + ReadBytes *wireInt64 `json:"read_bytes,omitempty"` + RowsProducedCount *wireInt64 `json:"rows_produced_count,omitempty"` + CompilationTimeMs *wireInt64 `json:"compilation_time_ms,omitempty"` + ExecutionTimeMs *wireInt64 `json:"execution_time_ms,omitempty"` + ReadRemoteBytes *wireInt64 `json:"read_remote_bytes,omitempty"` + WriteRemoteBytes *wireInt64 `json:"write_remote_bytes,omitempty"` + ReadCacheBytes *wireInt64 `json:"read_cache_bytes,omitempty"` + SpillToDiskBytes *wireInt64 `json:"spill_to_disk_bytes,omitempty"` + TaskTotalTimeMs *wireInt64 `json:"task_total_time_ms,omitempty"` + ReadFilesCount *wireInt64 `json:"read_files_count,omitempty"` + ReadPartitionsCount *wireInt64 `json:"read_partitions_count,omitempty"` + PhotonTotalTimeMs *wireInt64 `json:"photon_total_time_ms,omitempty"` + RowsReadCount *wireInt64 `json:"rows_read_count,omitempty"` + ResultFetchTimeMs *wireInt64 `json:"result_fetch_time_ms,omitempty"` + NetworkSentBytes *wireInt64 `json:"network_sent_bytes,omitempty"` ResultFromCache *bool `json:"result_from_cache,omitempty"` - PrunedBytes *int64 `json:"pruned_bytes,omitempty"` - PrunedFilesCount *int64 `json:"pruned_files_count,omitempty"` - ProvisioningQueueStartTimestamp *int64 `json:"provisioning_queue_start_timestamp,omitempty"` - OverloadingQueueStartTimestamp *int64 `json:"overloading_queue_start_timestamp,omitempty"` - QueryCompilationStartTimestamp *int64 `json:"query_compilation_start_timestamp,omitempty"` + PrunedBytes *wireInt64 `json:"pruned_bytes,omitempty"` + PrunedFilesCount *wireInt64 `json:"pruned_files_count,omitempty"` + ProvisioningQueueStartTimestamp *wireInt64 `json:"provisioning_queue_start_timestamp,omitempty"` + OverloadingQueueStartTimestamp *wireInt64 `json:"overloading_queue_start_timestamp,omitempty"` + QueryCompilationStartTimestamp *wireInt64 `json:"query_compilation_start_timestamp,omitempty"` TaskTimeOverTimeRange *taskTimeOverRangeWire `json:"task_time_over_time_range,omitempty"` - WorkToBeDone *int64 `json:"work_to_be_done,omitempty"` - RunnableTasks *int64 `json:"runnable_tasks,omitempty"` - ProjectedRemainingTaskTotalTimeMs *int64 `json:"projected_remaining_task_total_time_ms,omitempty"` - RemainingTaskCount *int64 `json:"remaining_task_count,omitempty"` - ProjectedRemainingWallclockTimeMs *int64 `json:"projected_remaining_wallclock_time_ms,omitempty"` - ReadFilesBytes *int64 `json:"read_files_bytes,omitempty"` + WorkToBeDone *wireInt64 `json:"work_to_be_done,omitempty"` + RunnableTasks *wireInt64 `json:"runnable_tasks,omitempty"` + ProjectedRemainingTaskTotalTimeMs *wireInt64 `json:"projected_remaining_task_total_time_ms,omitempty"` + RemainingTaskCount *wireInt64 `json:"remaining_task_count,omitempty"` + ProjectedRemainingWallclockTimeMs *wireInt64 `json:"projected_remaining_wallclock_time_ms,omitempty"` + ReadFilesBytes *wireInt64 `json:"read_files_bytes,omitempty"` } func queryMetricsFromWire(w *queryMetricsWire) (*QueryMetrics, error) { if w == nil { return nil, nil } + totalTimeMsPublicValue, err := int64FromWire(w.TotalTimeMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.TotalTimeMs", err) + } + readBytesPublicValue, err := int64FromWire(w.ReadBytes) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.ReadBytes", err) + } + rowsProducedCountPublicValue, err := int64FromWire(w.RowsProducedCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.RowsProducedCount", err) + } + compilationTimeMsPublicValue, err := int64FromWire(w.CompilationTimeMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.CompilationTimeMs", err) + } + executionTimeMsPublicValue, err := int64FromWire(w.ExecutionTimeMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.ExecutionTimeMs", err) + } + readRemoteBytesPublicValue, err := int64FromWire(w.ReadRemoteBytes) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.ReadRemoteBytes", err) + } + writeRemoteBytesPublicValue, err := int64FromWire(w.WriteRemoteBytes) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.WriteRemoteBytes", err) + } + readCacheBytesPublicValue, err := int64FromWire(w.ReadCacheBytes) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.ReadCacheBytes", err) + } + spillToDiskBytesPublicValue, err := int64FromWire(w.SpillToDiskBytes) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.SpillToDiskBytes", err) + } + taskTotalTimeMsPublicValue, err := int64FromWire(w.TaskTotalTimeMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.TaskTotalTimeMs", err) + } + readFilesCountPublicValue, err := int64FromWire(w.ReadFilesCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.ReadFilesCount", err) + } + readPartitionsCountPublicValue, err := int64FromWire(w.ReadPartitionsCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.ReadPartitionsCount", err) + } + photonTotalTimeMsPublicValue, err := int64FromWire(w.PhotonTotalTimeMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.PhotonTotalTimeMs", err) + } + rowsReadCountPublicValue, err := int64FromWire(w.RowsReadCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.RowsReadCount", err) + } + resultFetchTimeMsPublicValue, err := int64FromWire(w.ResultFetchTimeMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.ResultFetchTimeMs", err) + } + networkSentBytesPublicValue, err := int64FromWire(w.NetworkSentBytes) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.NetworkSentBytes", err) + } + prunedBytesPublicValue, err := int64FromWire(w.PrunedBytes) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.PrunedBytes", err) + } + prunedFilesCountPublicValue, err := int64FromWire(w.PrunedFilesCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.PrunedFilesCount", err) + } + provisioningQueueStartTimestampPublicValue, err := int64FromWire(w.ProvisioningQueueStartTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.ProvisioningQueueStartTimestamp", err) + } + overloadingQueueStartTimestampPublicValue, err := int64FromWire(w.OverloadingQueueStartTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.OverloadingQueueStartTimestamp", err) + } + queryCompilationStartTimestampPublicValue, err := int64FromWire(w.QueryCompilationStartTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.QueryCompilationStartTimestamp", err) + } taskTimeOverTimeRangePublicValue, err := taskTimeOverRangeFromWire(w.TaskTimeOverTimeRange) if err != nil { return nil, fmt.Errorf("%s: %w", "QueryMetrics.TaskTimeOverTimeRange", err) } + workToBeDonePublicValue, err := int64FromWire(w.WorkToBeDone) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.WorkToBeDone", err) + } + runnableTasksPublicValue, err := int64FromWire(w.RunnableTasks) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.RunnableTasks", err) + } + projectedRemainingTaskTotalTimeMsPublicValue, err := int64FromWire(w.ProjectedRemainingTaskTotalTimeMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.ProjectedRemainingTaskTotalTimeMs", err) + } + remainingTaskCountPublicValue, err := int64FromWire(w.RemainingTaskCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.RemainingTaskCount", err) + } + projectedRemainingWallclockTimeMsPublicValue, err := int64FromWire(w.ProjectedRemainingWallclockTimeMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.ProjectedRemainingWallclockTimeMs", err) + } + readFilesBytesPublicValue, err := int64FromWire(w.ReadFilesBytes) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QueryMetrics.ReadFilesBytes", err) + } return &QueryMetrics{ - TotalTimeMs: w.TotalTimeMs, - ReadBytes: w.ReadBytes, - RowsProducedCount: w.RowsProducedCount, - CompilationTimeMs: w.CompilationTimeMs, - ExecutionTimeMs: w.ExecutionTimeMs, - ReadRemoteBytes: w.ReadRemoteBytes, - WriteRemoteBytes: w.WriteRemoteBytes, - ReadCacheBytes: w.ReadCacheBytes, - SpillToDiskBytes: w.SpillToDiskBytes, - TaskTotalTimeMs: w.TaskTotalTimeMs, - ReadFilesCount: w.ReadFilesCount, - ReadPartitionsCount: w.ReadPartitionsCount, - PhotonTotalTimeMs: w.PhotonTotalTimeMs, - RowsReadCount: w.RowsReadCount, - ResultFetchTimeMs: w.ResultFetchTimeMs, - NetworkSentBytes: w.NetworkSentBytes, + TotalTimeMs: totalTimeMsPublicValue, + ReadBytes: readBytesPublicValue, + RowsProducedCount: rowsProducedCountPublicValue, + CompilationTimeMs: compilationTimeMsPublicValue, + ExecutionTimeMs: executionTimeMsPublicValue, + ReadRemoteBytes: readRemoteBytesPublicValue, + WriteRemoteBytes: writeRemoteBytesPublicValue, + ReadCacheBytes: readCacheBytesPublicValue, + SpillToDiskBytes: spillToDiskBytesPublicValue, + TaskTotalTimeMs: taskTotalTimeMsPublicValue, + ReadFilesCount: readFilesCountPublicValue, + ReadPartitionsCount: readPartitionsCountPublicValue, + PhotonTotalTimeMs: photonTotalTimeMsPublicValue, + RowsReadCount: rowsReadCountPublicValue, + ResultFetchTimeMs: resultFetchTimeMsPublicValue, + NetworkSentBytes: networkSentBytesPublicValue, ResultFromCache: w.ResultFromCache, - PrunedBytes: w.PrunedBytes, - PrunedFilesCount: w.PrunedFilesCount, - ProvisioningQueueStartTimestamp: w.ProvisioningQueueStartTimestamp, - OverloadingQueueStartTimestamp: w.OverloadingQueueStartTimestamp, - QueryCompilationStartTimestamp: w.QueryCompilationStartTimestamp, + PrunedBytes: prunedBytesPublicValue, + PrunedFilesCount: prunedFilesCountPublicValue, + ProvisioningQueueStartTimestamp: provisioningQueueStartTimestampPublicValue, + OverloadingQueueStartTimestamp: overloadingQueueStartTimestampPublicValue, + QueryCompilationStartTimestamp: queryCompilationStartTimestampPublicValue, TaskTimeOverTimeRange: taskTimeOverTimeRangePublicValue, - WorkToBeDone: w.WorkToBeDone, - RunnableTasks: w.RunnableTasks, - ProjectedRemainingTaskTotalTimeMs: w.ProjectedRemainingTaskTotalTimeMs, - RemainingTaskCount: w.RemainingTaskCount, - ProjectedRemainingWallclockTimeMs: w.ProjectedRemainingWallclockTimeMs, - ReadFilesBytes: w.ReadFilesBytes, + WorkToBeDone: workToBeDonePublicValue, + RunnableTasks: runnableTasksPublicValue, + ProjectedRemainingTaskTotalTimeMs: projectedRemainingTaskTotalTimeMsPublicValue, + RemainingTaskCount: remainingTaskCountPublicValue, + ProjectedRemainingWallclockTimeMs: projectedRemainingWallclockTimeMsPublicValue, + ReadFilesBytes: readFilesBytesPublicValue, }, nil } @@ -307,7 +493,7 @@ func queryTagFromWire(w *queryTagWire) (*QueryTag, error) { type taskTimeOverRangeWire struct { Entries []taskTimeOverRangeEntryWire `json:"entries,omitempty"` - Interval *int64 `json:"interval,omitempty"` + Interval *wireInt64 `json:"interval,omitempty"` } func taskTimeOverRangeFromWire(w *taskTimeOverRangeWire) (*TaskTimeOverRange, error) { @@ -318,37 +504,53 @@ func taskTimeOverRangeFromWire(w *taskTimeOverRangeWire) (*TaskTimeOverRange, er if err != nil { return nil, fmt.Errorf("%s: %w", "TaskTimeOverRange.Entries", err) } + intervalPublicValue, err := int64FromWire(w.Interval) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TaskTimeOverRange.Interval", err) + } return &TaskTimeOverRange{ Entries: entriesPublicValue, - Interval: w.Interval, + Interval: intervalPublicValue, }, nil } type taskTimeOverRangeEntryWire struct { - TaskCompletedTimeMs *int64 `json:"task_completed_time_ms,omitempty"` + TaskCompletedTimeMs *wireInt64 `json:"task_completed_time_ms,omitempty"` } func taskTimeOverRangeEntryFromWire(w *taskTimeOverRangeEntryWire) (*TaskTimeOverRangeEntry, error) { if w == nil { return nil, nil } + taskCompletedTimeMsPublicValue, err := int64FromWire(w.TaskCompletedTimeMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TaskTimeOverRangeEntry.TaskCompletedTimeMs", err) + } return &TaskTimeOverRangeEntry{ - TaskCompletedTimeMs: w.TaskCompletedTimeMs, + TaskCompletedTimeMs: taskCompletedTimeMsPublicValue, }, nil } type timeRangeWire struct { - StartTimeMs *int64 `json:"start_time_ms,omitempty"` - EndTimeMs *int64 `json:"end_time_ms,omitempty"` + StartTimeMs *wireInt64 `json:"start_time_ms,omitempty"` + EndTimeMs *wireInt64 `json:"end_time_ms,omitempty"` } func timeRangeToWire(v *TimeRange) (*timeRangeWire, error) { if v == nil { return nil, nil } + startTimeMsWireValue, err := int64ToWire(v.StartTimeMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TimeRange.StartTimeMs", err) + } + endTimeMsWireValue, err := int64ToWire(v.EndTimeMs) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TimeRange.EndTimeMs", err) + } return &timeRangeWire{ - StartTimeMs: v.StartTimeMs, - EndTimeMs: v.EndTimeMs, + StartTimeMs: startTimeMsWireValue, + EndTimeMs: endTimeMsWireValue, }, nil } diff --git a/repos/CHANGELOG.md b/repos/CHANGELOG.md index 6224c04..19f237c 100644 --- a/repos/CHANGELOG.md +++ b/repos/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/repos/go.mod b/repos/go.mod index 71f518e..6e41448 100644 --- a/repos/go.mod +++ b/repos/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/repos/internal/version.go b/repos/internal/version.go index 9ecd0f9..624c515 100644 --- a/repos/internal/version.go +++ b/repos/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-repos" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/repos/v1/client.go b/repos/v1/client.go old mode 100755 new mode 100644 index 963b5fd..5dd76e7 --- a/repos/v1/client.go +++ b/repos/v1/client.go @@ -77,8 +77,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Creates a repo in the workspace and links it to the remote Git repo // specified. Note that repos created programmatically must be linked to a // remote Git repo, unlike repos created in the browser. -func (c *internalClient) CreateRepo(ctx context.Context, req *CreateRepoRequest, opts ...call.Option) (*CreateRepoResponse, error) { - wireReq, err := createRepoRequestToWire(req) +func (c *internalClient) CreateRepo(ctx context.Context, req CreateRepoRequest, opts ...call.Option) (*CreateRepoResponse, error) { + wireReq, err := createRepoRequestToWire(&req) if err != nil { return nil, err } @@ -143,7 +143,7 @@ func (c *internalClient) CreateRepo(ctx context.Context, req *CreateRepoRequest, } // Deletes the specified repo. -func (c *internalClient) DeleteRepo(ctx context.Context, req *DeleteRepoRequest, opts ...call.Option) (*DeleteRepoResponse, error) { +func (c *internalClient) DeleteRepo(ctx context.Context, req DeleteRepoRequest, opts ...call.Option) (*DeleteRepoResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -157,7 +157,11 @@ func (c *internalClient) DeleteRepo(ctx context.Context, req *DeleteRepoRequest, } pb := pathBuilder{} pb.literal("/api/2.0/repos/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -197,7 +201,7 @@ func (c *internalClient) DeleteRepo(ctx context.Context, req *DeleteRepoRequest, } // Returns the repo with the given repo ID. -func (c *internalClient) GetRepo(ctx context.Context, req *GetRepoRequest, opts ...call.Option) (*GetRepoResponse, error) { +func (c *internalClient) GetRepo(ctx context.Context, req GetRepoRequest, opts ...call.Option) (*GetRepoResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -211,7 +215,11 @@ func (c *internalClient) GetRepo(ctx context.Context, req *GetRepoRequest, opts } pb := pathBuilder{} pb.literal("/api/2.0/repos/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -263,8 +271,8 @@ func (c *internalClient) GetRepo(ctx context.Context, req *GetRepoRequest, opts // the workspace, because repos with the Git CLI enabled are not included in its // results. Instead, use the Repos and Workspace APIs to find repos and their // associated metadata in the workspace. -func (c *internalClient) ListRepos(ctx context.Context, req *ListReposRequest, opts ...call.Option) (*ListReposResponse, error) { - wireReq, err := listReposRequestToWire(req) +func (c *internalClient) ListRepos(ctx context.Context, req ListReposRequest, opts ...call.Option) (*ListReposResponse, error) { + wireReq, err := listReposRequestToWire(&req) if err != nil { return nil, err } @@ -334,7 +342,7 @@ func (c *internalClient) ListRepos(ctx context.Context, req *ListReposRequest, o // // For example: // -// for item, err := range c.ListReposIter(ctx, &ListReposRequest{}) { +// for item, err := range c.ListReposIter(ctx, ListReposRequest{}) { // if err != nil { // return err // } @@ -346,16 +354,13 @@ func (c *internalClient) ListRepos(ctx context.Context, req *ListReposRequest, o // // Callers who need custom pagination logic should use // ListRepos directly. -func (c *internalClient) ListReposIter(ctx context.Context, req *ListReposRequest, opts ...call.Option) iter.Seq2[*RepoInfo, error] { +func (c *internalClient) ListReposIter(ctx context.Context, req ListReposRequest, opts ...call.Option) iter.Seq2[*RepoInfo, error] { return func(yield func(*RepoInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListReposRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListRepos(ctx, &pageReq, opts...) + resp, err := c.ListRepos(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -375,8 +380,8 @@ func (c *internalClient) ListReposIter(ctx context.Context, req *ListReposReques // Updates the repo to a different branch or tag, or updates the repo to the // latest commit on the same branch. -func (c *internalClient) UpdateRepo(ctx context.Context, req *UpdateRepoRequest, opts ...call.Option) (*UpdateRepoResponse, error) { - wireReq, err := updateRepoRequestToWire(req) +func (c *internalClient) UpdateRepo(ctx context.Context, req UpdateRepoRequest, opts ...call.Option) (*UpdateRepoResponse, error) { + wireReq, err := updateRepoRequestToWire(&req) if err != nil { return nil, err } @@ -397,7 +402,11 @@ func (c *internalClient) UpdateRepo(ctx context.Context, req *UpdateRepoRequest, } pb := pathBuilder{} pb.literal("/api/2.0/repos/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/repos/v1/genhelper.go b/repos/v1/genhelper.go old mode 100755 new mode 100644 index 9521e86..cdf1c2e --- a/repos/v1/genhelper.go +++ b/repos/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/repos/v1/wire.go b/repos/v1/wire.go old mode 100755 new mode 100644 index 645bd86..3fb6145 --- a/repos/v1/wire.go +++ b/repos/v1/wire.go @@ -3,15 +3,61 @@ package repos import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type createRepoRequestWire struct { Url *string `json:"url,omitempty"` Provider *string `json:"provider,omitempty"` Path *string `json:"path,omitempty"` SparseCheckout *sparseCheckoutWire `json:"sparse_checkout,omitempty"` - GitCredentialId *int64 `json:"git_credential_id,omitempty"` + GitCredentialId *wireInt64 `json:"git_credential_id,omitempty"` } func createRepoRequestToWire(v *CreateRepoRequest) (*createRepoRequestWire, error) { @@ -22,17 +68,21 @@ func createRepoRequestToWire(v *CreateRepoRequest) (*createRepoRequestWire, erro if err != nil { return nil, fmt.Errorf("%s: %w", "CreateRepoRequest.SparseCheckout", err) } + gitCredentialIdWireValue, err := int64ToWire(v.GitCredentialId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateRepoRequest.GitCredentialId", err) + } return &createRepoRequestWire{ Url: v.Url, Provider: v.Provider, Path: v.Path, SparseCheckout: sparseCheckoutWireValue, - GitCredentialId: v.GitCredentialId, + GitCredentialId: gitCredentialIdWireValue, }, nil } type createRepoResponseWire struct { - Id *int64 `json:"id,omitempty"` + Id *wireInt64 `json:"id,omitempty"` Path *string `json:"path,omitempty"` Url *string `json:"url,omitempty"` Provider *string `json:"provider,omitempty"` @@ -45,12 +95,16 @@ func createRepoResponseFromWire(w *createRepoResponseWire) (*CreateRepoResponse, if w == nil { return nil, nil } + idPublicValue, err := int64FromWire(w.Id) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateRepoResponse.Id", err) + } sparseCheckoutPublicValue, err := sparseCheckoutFromWire(w.SparseCheckout) if err != nil { return nil, fmt.Errorf("%s: %w", "CreateRepoResponse.SparseCheckout", err) } return &CreateRepoResponse{ - Id: w.Id, + Id: idPublicValue, Path: w.Path, Url: w.Url, Provider: w.Provider, @@ -61,7 +115,7 @@ func createRepoResponseFromWire(w *createRepoResponseWire) (*CreateRepoResponse, } type getRepoResponseWire struct { - Id *int64 `json:"id,omitempty"` + Id *wireInt64 `json:"id,omitempty"` Path *string `json:"path,omitempty"` Url *string `json:"url,omitempty"` Provider *string `json:"provider,omitempty"` @@ -75,12 +129,16 @@ func getRepoResponseFromWire(w *getRepoResponseWire) (*GetRepoResponse, error) { if w == nil { return nil, nil } + idPublicValue, err := int64FromWire(w.Id) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetRepoResponse.Id", err) + } sparseCheckoutPublicValue, err := sparseCheckoutFromWire(w.SparseCheckout) if err != nil { return nil, fmt.Errorf("%s: %w", "GetRepoResponse.SparseCheckout", err) } return &GetRepoResponse{ - Id: w.Id, + Id: idPublicValue, Path: w.Path, Url: w.Url, Provider: w.Provider, @@ -126,7 +184,7 @@ func listReposResponseFromWire(w *listReposResponseWire) (*ListReposResponse, er } type repoInfoWire struct { - Id *int64 `json:"id,omitempty"` + Id *wireInt64 `json:"id,omitempty"` Path *string `json:"path,omitempty"` Url *string `json:"url,omitempty"` Provider *string `json:"provider,omitempty"` @@ -139,12 +197,16 @@ func repoInfoFromWire(w *repoInfoWire) (*RepoInfo, error) { if w == nil { return nil, nil } + idPublicValue, err := int64FromWire(w.Id) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RepoInfo.Id", err) + } sparseCheckoutPublicValue, err := sparseCheckoutFromWire(w.SparseCheckout) if err != nil { return nil, fmt.Errorf("%s: %w", "RepoInfo.SparseCheckout", err) } return &RepoInfo{ - Id: w.Id, + Id: idPublicValue, Path: w.Path, Url: w.Url, Provider: w.Provider, @@ -190,29 +252,37 @@ func sparseCheckoutUpdateToWire(v *SparseCheckoutUpdate) (*sparseCheckoutUpdateW } type updateRepoRequestWire struct { - Id *int64 `json:"id,omitempty"` + Id *wireInt64 `json:"id,omitempty"` Branch *string `json:"branch,omitempty"` Tag *string `json:"tag,omitempty"` SparseCheckout *sparseCheckoutUpdateWire `json:"sparse_checkout,omitempty"` DangerouslyForceDiscardAll *bool `json:"dangerously_force_discard_all,omitempty"` - GitCredentialId *int64 `json:"git_credential_id,omitempty"` + GitCredentialId *wireInt64 `json:"git_credential_id,omitempty"` } func updateRepoRequestToWire(v *UpdateRepoRequest) (*updateRepoRequestWire, error) { if v == nil { return nil, nil } + idWireValue, err := int64ToWire(v.Id) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateRepoRequest.Id", err) + } sparseCheckoutWireValue, err := sparseCheckoutUpdateToWire(v.SparseCheckout) if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateRepoRequest.SparseCheckout", err) } + gitCredentialIdWireValue, err := int64ToWire(v.GitCredentialId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateRepoRequest.GitCredentialId", err) + } return &updateRepoRequestWire{ - Id: v.Id, + Id: idWireValue, Branch: v.Branch, Tag: v.Tag, SparseCheckout: sparseCheckoutWireValue, DangerouslyForceDiscardAll: v.DangerouslyForceDiscardAll, - GitCredentialId: v.GitCredentialId, + GitCredentialId: gitCredentialIdWireValue, }, nil } diff --git a/scim/CHANGELOG.md b/scim/CHANGELOG.md index 6224c04..19f237c 100644 --- a/scim/CHANGELOG.md +++ b/scim/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/scim/go.mod b/scim/go.mod index 44e6d32..2ac4c68 100644 --- a/scim/go.mod +++ b/scim/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/scim/internal/version.go b/scim/internal/version.go index 8242554..c2b17da 100644 --- a/scim/internal/version.go +++ b/scim/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-scim" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/scim/v1/client.go b/scim/v1/client.go old mode 100755 new mode 100644 index fed7749..1a83e2e --- a/scim/v1/client.go +++ b/scim/v1/client.go @@ -77,8 +77,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Creates a group in the account with a unique name, using the // supplied group details. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateAccountGroup(ctx context.Context, req *CreateAccountGroupRequest, opts ...call.Option) (*AccountGroup, error) { - wireReq, err := createAccountGroupRequestToWire(req) +func (c *internalClient) CreateAccountGroup(ctx context.Context, req CreateAccountGroupRequest, opts ...call.Option) (*AccountGroup, error) { + wireReq, err := createAccountGroupRequestToWire(&req) if err != nil { return nil, err } @@ -149,7 +149,7 @@ func (c *internalClient) CreateAccountGroup(ctx context.Context, req *CreateAcco // Deletes a group from the account. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteAccountGroup(ctx context.Context, req *DeleteAccountGroupRequest, opts ...call.Option) error { +func (c *internalClient) DeleteAccountGroup(ctx context.Context, req DeleteAccountGroupRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -166,7 +166,11 @@ func (c *internalClient) DeleteAccountGroup(ctx context.Context, req *DeleteAcco pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/scim/v2/Groups/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -204,7 +208,7 @@ func (c *internalClient) DeleteAccountGroup(ctx context.Context, req *DeleteAcco // Gets the information for a specific group in the account. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetAccountGroup(ctx context.Context, req *GetAccountGroupRequest, opts ...call.Option) (*AccountGroup, error) { +func (c *internalClient) GetAccountGroup(ctx context.Context, req GetAccountGroupRequest, opts ...call.Option) (*AccountGroup, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -221,7 +225,11 @@ func (c *internalClient) GetAccountGroup(ctx context.Context, req *GetAccountGro pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/scim/v2/Groups/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -272,8 +280,8 @@ func (c *internalClient) GetAccountGroup(ctx context.Context, req *GetAccountGro // accounts that rely on this attribute will not be impacted and will continue // receiving member data as before. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListAccountGroups(ctx context.Context, req *ListAccountGroupsRequest, opts ...call.Option) (*ListAccountGroupsResponse, error) { - wireReq, err := listAccountGroupsRequestToWire(req) +func (c *internalClient) ListAccountGroups(ctx context.Context, req ListAccountGroupsRequest, opts ...call.Option) (*ListAccountGroupsResponse, error) { + wireReq, err := listAccountGroupsRequestToWire(&req) if err != nil { return nil, err } @@ -365,7 +373,7 @@ func (c *internalClient) ListAccountGroups(ctx context.Context, req *ListAccount // // For example: // -// for item, err := range c.ListAccountGroupsIter(ctx, &ListAccountGroupsRequest{}) { +// for item, err := range c.ListAccountGroupsIter(ctx, ListAccountGroupsRequest{}) { // if err != nil { // return err // } @@ -377,16 +385,13 @@ func (c *internalClient) ListAccountGroups(ctx context.Context, req *ListAccount // // Callers who need custom pagination logic should use // ListAccountGroups directly. -func (c *internalClient) ListAccountGroupsIter(ctx context.Context, req *ListAccountGroupsRequest, opts ...call.Option) iter.Seq2[*AccountGroup, error] { +func (c *internalClient) ListAccountGroupsIter(ctx context.Context, req ListAccountGroupsRequest, opts ...call.Option) iter.Seq2[*AccountGroup, error] { return func(yield func(*AccountGroup, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListAccountGroupsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListAccountGroups(ctx, &pageReq, opts...) + resp, err := c.ListAccountGroups(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -411,8 +416,8 @@ func (c *internalClient) ListAccountGroupsIter(ctx context.Context, req *ListAcc // Partially updates the details of a group. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) PatchAccountGroup(ctx context.Context, req *PatchAccountGroupRequest, opts ...call.Option) error { - wireReq, err := patchAccountGroupRequestToWire(req) +func (c *internalClient) PatchAccountGroup(ctx context.Context, req PatchAccountGroupRequest, opts ...call.Option) error { + wireReq, err := patchAccountGroupRequestToWire(&req) if err != nil { return err } @@ -436,7 +441,11 @@ func (c *internalClient) PatchAccountGroup(ctx context.Context, req *PatchAccoun pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/scim/v2/Groups/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -475,8 +484,8 @@ func (c *internalClient) PatchAccountGroup(ctx context.Context, req *PatchAccoun // Updates the details of a group by replacing the entire group entity. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdateAccountGroup(ctx context.Context, req *UpdateAccountGroupRequest, opts ...call.Option) error { - wireReq, err := updateAccountGroupRequestToWire(req) +func (c *internalClient) UpdateAccountGroup(ctx context.Context, req UpdateAccountGroupRequest, opts ...call.Option) error { + wireReq, err := updateAccountGroupRequestToWire(&req) if err != nil { return err } @@ -500,7 +509,11 @@ func (c *internalClient) UpdateAccountGroup(ctx context.Context, req *UpdateAcco pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/scim/v2/Groups/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -539,8 +552,8 @@ func (c *internalClient) UpdateAccountGroup(ctx context.Context, req *UpdateAcco // Creates a new service principal in the account. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateAccountServicePrincipal(ctx context.Context, req *CreateAccountServicePrincipalRequest, opts ...call.Option) (*AccountServicePrincipal, error) { - wireReq, err := createAccountServicePrincipalRequestToWire(req) +func (c *internalClient) CreateAccountServicePrincipal(ctx context.Context, req CreateAccountServicePrincipalRequest, opts ...call.Option) (*AccountServicePrincipal, error) { + wireReq, err := createAccountServicePrincipalRequestToWire(&req) if err != nil { return nil, err } @@ -611,7 +624,7 @@ func (c *internalClient) CreateAccountServicePrincipal(ctx context.Context, req // Delete a single service principal in the account. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteAccountServicePrincipal(ctx context.Context, req *DeleteAccountServicePrincipalRequest, opts ...call.Option) error { +func (c *internalClient) DeleteAccountServicePrincipal(ctx context.Context, req DeleteAccountServicePrincipalRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -628,7 +641,11 @@ func (c *internalClient) DeleteAccountServicePrincipal(ctx context.Context, req pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/scim/v2/ServicePrincipals/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -667,7 +684,7 @@ func (c *internalClient) DeleteAccountServicePrincipal(ctx context.Context, req // Gets the details for a single service principal define in the // account. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetAccountServicePrincipal(ctx context.Context, req *GetAccountServicePrincipalRequest, opts ...call.Option) (*AccountServicePrincipal, error) { +func (c *internalClient) GetAccountServicePrincipal(ctx context.Context, req GetAccountServicePrincipalRequest, opts ...call.Option) (*AccountServicePrincipal, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -684,7 +701,11 @@ func (c *internalClient) GetAccountServicePrincipal(ctx context.Context, req *Ge pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/scim/v2/ServicePrincipals/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -731,8 +752,8 @@ func (c *internalClient) GetAccountServicePrincipal(ctx context.Context, req *Ge // Gets the set of service principals associated with a account. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListAccountServicePrincipals(ctx context.Context, req *ListAccountServicePrincipalsRequest, opts ...call.Option) (*ListAccountServicePrincipalsResponse, error) { - wireReq, err := listAccountServicePrincipalsRequestToWire(req) +func (c *internalClient) ListAccountServicePrincipals(ctx context.Context, req ListAccountServicePrincipalsRequest, opts ...call.Option) (*ListAccountServicePrincipalsResponse, error) { + wireReq, err := listAccountServicePrincipalsRequestToWire(&req) if err != nil { return nil, err } @@ -824,7 +845,7 @@ func (c *internalClient) ListAccountServicePrincipals(ctx context.Context, req * // // For example: // -// for item, err := range c.ListAccountServicePrincipalsIter(ctx, &ListAccountServicePrincipalsRequest{}) { +// for item, err := range c.ListAccountServicePrincipalsIter(ctx, ListAccountServicePrincipalsRequest{}) { // if err != nil { // return err // } @@ -836,16 +857,13 @@ func (c *internalClient) ListAccountServicePrincipals(ctx context.Context, req * // // Callers who need custom pagination logic should use // ListAccountServicePrincipals directly. -func (c *internalClient) ListAccountServicePrincipalsIter(ctx context.Context, req *ListAccountServicePrincipalsRequest, opts ...call.Option) iter.Seq2[*AccountServicePrincipal, error] { +func (c *internalClient) ListAccountServicePrincipalsIter(ctx context.Context, req ListAccountServicePrincipalsRequest, opts ...call.Option) iter.Seq2[*AccountServicePrincipal, error] { return func(yield func(*AccountServicePrincipal, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListAccountServicePrincipalsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListAccountServicePrincipals(ctx, &pageReq, opts...) + resp, err := c.ListAccountServicePrincipals(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -871,8 +889,8 @@ func (c *internalClient) ListAccountServicePrincipalsIter(ctx context.Context, r // Partially updates the details of a single service principal in the // account. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) PatchAccountServicePrincipal(ctx context.Context, req *PatchAccountServicePrincipalRequest, opts ...call.Option) error { - wireReq, err := patchAccountServicePrincipalRequestToWire(req) +func (c *internalClient) PatchAccountServicePrincipal(ctx context.Context, req PatchAccountServicePrincipalRequest, opts ...call.Option) error { + wireReq, err := patchAccountServicePrincipalRequestToWire(&req) if err != nil { return err } @@ -896,7 +914,11 @@ func (c *internalClient) PatchAccountServicePrincipal(ctx context.Context, req * pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/scim/v2/ServicePrincipals/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -937,8 +959,8 @@ func (c *internalClient) PatchAccountServicePrincipal(ctx context.Context, req * // // This action replaces the existing service principal with the same name. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdateAccountServicePrincipal(ctx context.Context, req *UpdateAccountServicePrincipalRequest, opts ...call.Option) error { - wireReq, err := updateAccountServicePrincipalRequestToWire(req) +func (c *internalClient) UpdateAccountServicePrincipal(ctx context.Context, req UpdateAccountServicePrincipalRequest, opts ...call.Option) error { + wireReq, err := updateAccountServicePrincipalRequestToWire(&req) if err != nil { return err } @@ -962,7 +984,11 @@ func (c *internalClient) UpdateAccountServicePrincipal(ctx context.Context, req pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/scim/v2/ServicePrincipals/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1002,8 +1028,8 @@ func (c *internalClient) UpdateAccountServicePrincipal(ctx context.Context, req // Creates a new user in the account. This new user will also be // added to the account. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateAccountUser(ctx context.Context, req *CreateAccountUserRequest, opts ...call.Option) (*AccountUser, error) { - wireReq, err := createAccountUserRequestToWire(req) +func (c *internalClient) CreateAccountUser(ctx context.Context, req CreateAccountUserRequest, opts ...call.Option) (*AccountUser, error) { + wireReq, err := createAccountUserRequestToWire(&req) if err != nil { return nil, err } @@ -1075,7 +1101,7 @@ func (c *internalClient) CreateAccountUser(ctx context.Context, req *CreateAccou // Deletes a user. Deleting a user from a account also removes // objects associated with the user. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteAccountUser(ctx context.Context, req *DeleteAccountUserRequest, opts ...call.Option) error { +func (c *internalClient) DeleteAccountUser(ctx context.Context, req DeleteAccountUserRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1092,7 +1118,11 @@ func (c *internalClient) DeleteAccountUser(ctx context.Context, req *DeleteAccou pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/scim/v2/Users/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1130,8 +1160,8 @@ func (c *internalClient) DeleteAccountUser(ctx context.Context, req *DeleteAccou // Gets information for a specific user in account. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetAccountUser(ctx context.Context, req *GetAccountUserRequest, opts ...call.Option) (*AccountUser, error) { - wireReq, err := getAccountUserRequestToWire(req) +func (c *internalClient) GetAccountUser(ctx context.Context, req GetAccountUserRequest, opts ...call.Option) (*AccountUser, error) { + wireReq, err := getAccountUserRequestToWire(&req) if err != nil { return nil, err } @@ -1151,7 +1181,11 @@ func (c *internalClient) GetAccountUser(ctx context.Context, req *GetAccountUser pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/scim/v2/Users/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "attributes", wireReq.Attributes); err != nil { @@ -1221,8 +1255,8 @@ func (c *internalClient) GetAccountUser(ctx context.Context, req *GetAccountUser // Gets details for all the users associated with a account. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListAccountUsers(ctx context.Context, req *ListAccountUsersRequest, opts ...call.Option) (*ListAccountUsersResponse, error) { - wireReq, err := listAccountUsersRequestToWire(req) +func (c *internalClient) ListAccountUsers(ctx context.Context, req ListAccountUsersRequest, opts ...call.Option) (*ListAccountUsersResponse, error) { + wireReq, err := listAccountUsersRequestToWire(&req) if err != nil { return nil, err } @@ -1314,7 +1348,7 @@ func (c *internalClient) ListAccountUsers(ctx context.Context, req *ListAccountU // // For example: // -// for item, err := range c.ListAccountUsersIter(ctx, &ListAccountUsersRequest{}) { +// for item, err := range c.ListAccountUsersIter(ctx, ListAccountUsersRequest{}) { // if err != nil { // return err // } @@ -1326,16 +1360,13 @@ func (c *internalClient) ListAccountUsers(ctx context.Context, req *ListAccountU // // Callers who need custom pagination logic should use // ListAccountUsers directly. -func (c *internalClient) ListAccountUsersIter(ctx context.Context, req *ListAccountUsersRequest, opts ...call.Option) iter.Seq2[*AccountUser, error] { +func (c *internalClient) ListAccountUsersIter(ctx context.Context, req ListAccountUsersRequest, opts ...call.Option) iter.Seq2[*AccountUser, error] { return func(yield func(*AccountUser, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListAccountUsersRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListAccountUsers(ctx, &pageReq, opts...) + resp, err := c.ListAccountUsers(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1362,8 +1393,8 @@ func (c *internalClient) ListAccountUsersIter(ctx context.Context, req *ListAcco // specific user attributes. The `userName` and `emails` attributes cannot be // updated through this API; any supplied changes to them are ignored (no-op). // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) PatchAccountUser(ctx context.Context, req *PatchAccountUserRequest, opts ...call.Option) error { - wireReq, err := patchAccountUserRequestToWire(req) +func (c *internalClient) PatchAccountUser(ctx context.Context, req PatchAccountUserRequest, opts ...call.Option) error { + wireReq, err := patchAccountUserRequestToWire(&req) if err != nil { return err } @@ -1387,7 +1418,11 @@ func (c *internalClient) PatchAccountUser(ctx context.Context, req *PatchAccount pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/scim/v2/Users/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1428,8 +1463,8 @@ func (c *internalClient) PatchAccountUser(ctx context.Context, req *PatchAccount // `userName` and `emails` attributes cannot be updated through this API; any // supplied changes to them are ignored (no-op). // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdateAccountUser(ctx context.Context, req *UpdateAccountUserRequest, opts ...call.Option) error { - wireReq, err := updateAccountUserRequestToWire(req) +func (c *internalClient) UpdateAccountUser(ctx context.Context, req UpdateAccountUserRequest, opts ...call.Option) error { + wireReq, err := updateAccountUserRequestToWire(&req) if err != nil { return err } @@ -1453,7 +1488,11 @@ func (c *internalClient) UpdateAccountUser(ctx context.Context, req *UpdateAccou pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/scim/v2/Users/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1491,8 +1530,8 @@ func (c *internalClient) UpdateAccountUser(ctx context.Context, req *UpdateAccou } // Get details about the current method caller's identity. -func (c *internalClient) Me(ctx context.Context, req *MeRequest, opts ...call.Option) (*User, error) { - wireReq, err := meRequestToWire(req) +func (c *internalClient) Me(ctx context.Context, req MeRequest, opts ...call.Option) (*User, error) { + wireReq, err := meRequestToWire(&req) if err != nil { return nil, err } @@ -1559,8 +1598,8 @@ func (c *internalClient) Me(ctx context.Context, req *MeRequest, opts ...call.Op // Creates a group in the workspace with a unique name, using the // supplied group details. -func (c *internalClient) CreateGroup(ctx context.Context, req *CreateGroupRequest, opts ...call.Option) (*Group, error) { - wireReq, err := createGroupRequestToWire(req) +func (c *internalClient) CreateGroup(ctx context.Context, req CreateGroupRequest, opts ...call.Option) (*Group, error) { + wireReq, err := createGroupRequestToWire(&req) if err != nil { return nil, err } @@ -1625,7 +1664,7 @@ func (c *internalClient) CreateGroup(ctx context.Context, req *CreateGroupReques } // Deletes a group from the workspace. -func (c *internalClient) DeleteGroup(ctx context.Context, req *DeleteGroupRequest, opts ...call.Option) error { +func (c *internalClient) DeleteGroup(ctx context.Context, req DeleteGroupRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1639,7 +1678,11 @@ func (c *internalClient) DeleteGroup(ctx context.Context, req *DeleteGroupReques } pb := pathBuilder{} pb.literal("/api/2.0/preview/scim/v2/Groups/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1676,7 +1719,7 @@ func (c *internalClient) DeleteGroup(ctx context.Context, req *DeleteGroupReques } // Gets the information for a specific group in the workspace. -func (c *internalClient) GetGroup(ctx context.Context, req *GetGroupRequest, opts ...call.Option) (*Group, error) { +func (c *internalClient) GetGroup(ctx context.Context, req GetGroupRequest, opts ...call.Option) (*Group, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1690,7 +1733,11 @@ func (c *internalClient) GetGroup(ctx context.Context, req *GetGroupRequest, opt } pb := pathBuilder{} pb.literal("/api/2.0/preview/scim/v2/Groups/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1736,8 +1783,8 @@ func (c *internalClient) GetGroup(ctx context.Context, req *GetGroupRequest, opt } // Gets all details of the groups associated with the workspace. -func (c *internalClient) ListGroups(ctx context.Context, req *ListGroupsRequest, opts ...call.Option) (*ListGroupsResponse, error) { - wireReq, err := listGroupsRequestToWire(req) +func (c *internalClient) ListGroups(ctx context.Context, req ListGroupsRequest, opts ...call.Option) (*ListGroupsResponse, error) { + wireReq, err := listGroupsRequestToWire(&req) if err != nil { return nil, err } @@ -1824,7 +1871,7 @@ func (c *internalClient) ListGroups(ctx context.Context, req *ListGroupsRequest, // // For example: // -// for item, err := range c.ListGroupsIter(ctx, &ListGroupsRequest{}) { +// for item, err := range c.ListGroupsIter(ctx, ListGroupsRequest{}) { // if err != nil { // return err // } @@ -1836,16 +1883,13 @@ func (c *internalClient) ListGroups(ctx context.Context, req *ListGroupsRequest, // // Callers who need custom pagination logic should use // ListGroups directly. -func (c *internalClient) ListGroupsIter(ctx context.Context, req *ListGroupsRequest, opts ...call.Option) iter.Seq2[*Group, error] { +func (c *internalClient) ListGroupsIter(ctx context.Context, req ListGroupsRequest, opts ...call.Option) iter.Seq2[*Group, error] { return func(yield func(*Group, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListGroupsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListGroups(ctx, &pageReq, opts...) + resp, err := c.ListGroups(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1869,8 +1913,8 @@ func (c *internalClient) ListGroupsIter(ctx context.Context, req *ListGroupsRequ } // Partially updates the details of a group. -func (c *internalClient) PatchGroup(ctx context.Context, req *PatchGroupRequest, opts ...call.Option) error { - wireReq, err := patchGroupRequestToWire(req) +func (c *internalClient) PatchGroup(ctx context.Context, req PatchGroupRequest, opts ...call.Option) error { + wireReq, err := patchGroupRequestToWire(&req) if err != nil { return err } @@ -1891,7 +1935,11 @@ func (c *internalClient) PatchGroup(ctx context.Context, req *PatchGroupRequest, } pb := pathBuilder{} pb.literal("/api/2.0/preview/scim/v2/Groups/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1929,8 +1977,8 @@ func (c *internalClient) PatchGroup(ctx context.Context, req *PatchGroupRequest, } // Updates the details of a group by replacing the entire group entity. -func (c *internalClient) UpdateGroup(ctx context.Context, req *UpdateGroupRequest, opts ...call.Option) error { - wireReq, err := updateGroupRequestToWire(req) +func (c *internalClient) UpdateGroup(ctx context.Context, req UpdateGroupRequest, opts ...call.Option) error { + wireReq, err := updateGroupRequestToWire(&req) if err != nil { return err } @@ -1951,7 +1999,11 @@ func (c *internalClient) UpdateGroup(ctx context.Context, req *UpdateGroupReques } pb := pathBuilder{} pb.literal("/api/2.0/preview/scim/v2/Groups/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1989,8 +2041,8 @@ func (c *internalClient) UpdateGroup(ctx context.Context, req *UpdateGroupReques } // Creates a new service principal in the workspace. -func (c *internalClient) CreateServicePrincipal(ctx context.Context, req *CreateServicePrincipalRequest, opts ...call.Option) (*ServicePrincipal, error) { - wireReq, err := createServicePrincipalRequestToWire(req) +func (c *internalClient) CreateServicePrincipal(ctx context.Context, req CreateServicePrincipalRequest, opts ...call.Option) (*ServicePrincipal, error) { + wireReq, err := createServicePrincipalRequestToWire(&req) if err != nil { return nil, err } @@ -2055,7 +2107,7 @@ func (c *internalClient) CreateServicePrincipal(ctx context.Context, req *Create } // Delete a single service principal in the workspace. -func (c *internalClient) DeleteServicePrincipal(ctx context.Context, req *DeleteServicePrincipalRequest, opts ...call.Option) error { +func (c *internalClient) DeleteServicePrincipal(ctx context.Context, req DeleteServicePrincipalRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2069,7 +2121,11 @@ func (c *internalClient) DeleteServicePrincipal(ctx context.Context, req *Delete } pb := pathBuilder{} pb.literal("/api/2.0/preview/scim/v2/ServicePrincipals/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2107,7 +2163,7 @@ func (c *internalClient) DeleteServicePrincipal(ctx context.Context, req *Delete // Gets the details for a single service principal define in the // workspace. -func (c *internalClient) GetServicePrincipal(ctx context.Context, req *GetServicePrincipalRequest, opts ...call.Option) (*ServicePrincipal, error) { +func (c *internalClient) GetServicePrincipal(ctx context.Context, req GetServicePrincipalRequest, opts ...call.Option) (*ServicePrincipal, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2121,7 +2177,11 @@ func (c *internalClient) GetServicePrincipal(ctx context.Context, req *GetServic } pb := pathBuilder{} pb.literal("/api/2.0/preview/scim/v2/ServicePrincipals/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2167,8 +2227,8 @@ func (c *internalClient) GetServicePrincipal(ctx context.Context, req *GetServic } // Gets the set of service principals associated with a workspace. -func (c *internalClient) ListServicePrincipals(ctx context.Context, req *ListServicePrincipalsRequest, opts ...call.Option) (*ListServicePrincipalResponse, error) { - wireReq, err := listServicePrincipalsRequestToWire(req) +func (c *internalClient) ListServicePrincipals(ctx context.Context, req ListServicePrincipalsRequest, opts ...call.Option) (*ListServicePrincipalResponse, error) { + wireReq, err := listServicePrincipalsRequestToWire(&req) if err != nil { return nil, err } @@ -2255,7 +2315,7 @@ func (c *internalClient) ListServicePrincipals(ctx context.Context, req *ListSer // // For example: // -// for item, err := range c.ListServicePrincipalsIter(ctx, &ListServicePrincipalsRequest{}) { +// for item, err := range c.ListServicePrincipalsIter(ctx, ListServicePrincipalsRequest{}) { // if err != nil { // return err // } @@ -2267,16 +2327,13 @@ func (c *internalClient) ListServicePrincipals(ctx context.Context, req *ListSer // // Callers who need custom pagination logic should use // ListServicePrincipals directly. -func (c *internalClient) ListServicePrincipalsIter(ctx context.Context, req *ListServicePrincipalsRequest, opts ...call.Option) iter.Seq2[*ServicePrincipal, error] { +func (c *internalClient) ListServicePrincipalsIter(ctx context.Context, req ListServicePrincipalsRequest, opts ...call.Option) iter.Seq2[*ServicePrincipal, error] { return func(yield func(*ServicePrincipal, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListServicePrincipalsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListServicePrincipals(ctx, &pageReq, opts...) + resp, err := c.ListServicePrincipals(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -2301,8 +2358,8 @@ func (c *internalClient) ListServicePrincipalsIter(ctx context.Context, req *Lis // Partially updates the details of a single service principal in the // workspace. -func (c *internalClient) PatchServicePrincipal(ctx context.Context, req *PatchServicePrincipalRequest, opts ...call.Option) error { - wireReq, err := patchServicePrincipalRequestToWire(req) +func (c *internalClient) PatchServicePrincipal(ctx context.Context, req PatchServicePrincipalRequest, opts ...call.Option) error { + wireReq, err := patchServicePrincipalRequestToWire(&req) if err != nil { return err } @@ -2323,7 +2380,11 @@ func (c *internalClient) PatchServicePrincipal(ctx context.Context, req *PatchSe } pb := pathBuilder{} pb.literal("/api/2.0/preview/scim/v2/ServicePrincipals/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2363,8 +2424,8 @@ func (c *internalClient) PatchServicePrincipal(ctx context.Context, req *PatchSe // Updates the details of a single service principal. // // This action replaces the existing service principal with the same name. -func (c *internalClient) UpdateServicePrincipal(ctx context.Context, req *UpdateServicePrincipalRequest, opts ...call.Option) error { - wireReq, err := updateServicePrincipalRequestToWire(req) +func (c *internalClient) UpdateServicePrincipal(ctx context.Context, req UpdateServicePrincipalRequest, opts ...call.Option) error { + wireReq, err := updateServicePrincipalRequestToWire(&req) if err != nil { return err } @@ -2385,7 +2446,11 @@ func (c *internalClient) UpdateServicePrincipal(ctx context.Context, req *Update } pb := pathBuilder{} pb.literal("/api/2.0/preview/scim/v2/ServicePrincipals/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2424,8 +2489,8 @@ func (c *internalClient) UpdateServicePrincipal(ctx context.Context, req *Update // Creates a new user in the workspace. This new user will also be // added to the account. -func (c *internalClient) CreateUser(ctx context.Context, req *CreateUserRequest, opts ...call.Option) (*User, error) { - wireReq, err := createUserRequestToWire(req) +func (c *internalClient) CreateUser(ctx context.Context, req CreateUserRequest, opts ...call.Option) (*User, error) { + wireReq, err := createUserRequestToWire(&req) if err != nil { return nil, err } @@ -2491,7 +2556,7 @@ func (c *internalClient) CreateUser(ctx context.Context, req *CreateUserRequest, // Deletes a user. Deleting a user from a workspace also removes // objects associated with the user. -func (c *internalClient) DeleteUser(ctx context.Context, req *DeleteUserRequest, opts ...call.Option) error { +func (c *internalClient) DeleteUser(ctx context.Context, req DeleteUserRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2505,7 +2570,11 @@ func (c *internalClient) DeleteUser(ctx context.Context, req *DeleteUserRequest, } pb := pathBuilder{} pb.literal("/api/2.0/preview/scim/v2/Users/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2542,7 +2611,7 @@ func (c *internalClient) DeleteUser(ctx context.Context, req *DeleteUserRequest, } // Gets the permission levels that a user can have on an object. -func (c *internalClient) GetPermissionLevels(ctx context.Context, req *GetPasswordPermissionLevelsRequest, opts ...call.Option) (*GetPasswordPermissionLevelsResponse, error) { +func (c *internalClient) GetPermissionLevels(ctx context.Context, req GetPasswordPermissionLevelsRequest, opts ...call.Option) (*GetPasswordPermissionLevelsResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2600,7 +2669,7 @@ func (c *internalClient) GetPermissionLevels(ctx context.Context, req *GetPasswo // Gets the permissions of all passwords. Passwords can inherit permissions from // their root object. -func (c *internalClient) GetPermissions(ctx context.Context, req *GetPasswordPermissionsRequest, opts ...call.Option) (*PasswordPermissions, error) { +func (c *internalClient) GetPermissions(ctx context.Context, req GetPasswordPermissionsRequest, opts ...call.Option) (*PasswordPermissions, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -2657,8 +2726,8 @@ func (c *internalClient) GetPermissions(ctx context.Context, req *GetPasswordPer } // Gets information for a specific user in workspace. -func (c *internalClient) GetUser(ctx context.Context, req *GetUserRequest, opts ...call.Option) (*User, error) { - wireReq, err := getUserRequestToWire(req) +func (c *internalClient) GetUser(ctx context.Context, req GetUserRequest, opts ...call.Option) (*User, error) { + wireReq, err := getUserRequestToWire(&req) if err != nil { return nil, err } @@ -2675,7 +2744,11 @@ func (c *internalClient) GetUser(ctx context.Context, req *GetUserRequest, opts } pb := pathBuilder{} pb.literal("/api/2.0/preview/scim/v2/Users/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "attributes", wireReq.Attributes); err != nil { @@ -2744,8 +2817,8 @@ func (c *internalClient) GetUser(ctx context.Context, req *GetUserRequest, opts } // Gets details for all the users associated with a workspace. -func (c *internalClient) ListUsers(ctx context.Context, req *ListUsersRequest, opts ...call.Option) (*ListUsersResponse, error) { - wireReq, err := listUsersRequestToWire(req) +func (c *internalClient) ListUsers(ctx context.Context, req ListUsersRequest, opts ...call.Option) (*ListUsersResponse, error) { + wireReq, err := listUsersRequestToWire(&req) if err != nil { return nil, err } @@ -2832,7 +2905,7 @@ func (c *internalClient) ListUsers(ctx context.Context, req *ListUsersRequest, o // // For example: // -// for item, err := range c.ListUsersIter(ctx, &ListUsersRequest{}) { +// for item, err := range c.ListUsersIter(ctx, ListUsersRequest{}) { // if err != nil { // return err // } @@ -2844,16 +2917,13 @@ func (c *internalClient) ListUsers(ctx context.Context, req *ListUsersRequest, o // // Callers who need custom pagination logic should use // ListUsers directly. -func (c *internalClient) ListUsersIter(ctx context.Context, req *ListUsersRequest, opts ...call.Option) iter.Seq2[*User, error] { +func (c *internalClient) ListUsersIter(ctx context.Context, req ListUsersRequest, opts ...call.Option) iter.Seq2[*User, error] { return func(yield func(*User, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListUsersRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListUsers(ctx, &pageReq, opts...) + resp, err := c.ListUsers(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -2879,8 +2949,8 @@ func (c *internalClient) ListUsersIter(ctx context.Context, req *ListUsersReques // Partially updates a user resource by applying the supplied operations on // specific user attributes. The `userName` and `emails` attributes cannot be // updated through this API; any supplied changes to them are ignored (no-op). -func (c *internalClient) PatchUser(ctx context.Context, req *PatchUserRequest, opts ...call.Option) error { - wireReq, err := patchUserRequestToWire(req) +func (c *internalClient) PatchUser(ctx context.Context, req PatchUserRequest, opts ...call.Option) error { + wireReq, err := patchUserRequestToWire(&req) if err != nil { return err } @@ -2901,7 +2971,11 @@ func (c *internalClient) PatchUser(ctx context.Context, req *PatchUserRequest, o } pb := pathBuilder{} pb.literal("/api/2.0/preview/scim/v2/Users/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2941,8 +3015,8 @@ func (c *internalClient) PatchUser(ctx context.Context, req *PatchUserRequest, o // Sets permissions on an object, replacing existing permissions if they exist. // Deletes all direct permissions if none are specified. Objects can inherit // permissions from their root object. -func (c *internalClient) SetPermissions(ctx context.Context, req *PasswordPermissionsRequest, opts ...call.Option) (*PasswordPermissions, error) { - wireReq, err := passwordPermissionsRequestToWire(req) +func (c *internalClient) SetPermissions(ctx context.Context, req PasswordPermissionsRequest, opts ...call.Option) (*PasswordPermissions, error) { + wireReq, err := passwordPermissionsRequestToWire(&req) if err != nil { return nil, err } @@ -3008,8 +3082,8 @@ func (c *internalClient) SetPermissions(ctx context.Context, req *PasswordPermis // Updates the permissions on all passwords. Passwords can inherit permissions // from their root object. -func (c *internalClient) UpdatePermissions(ctx context.Context, req *PasswordPermissionsRequest, opts ...call.Option) (*PasswordPermissions, error) { - wireReq, err := passwordPermissionsRequestToWire(req) +func (c *internalClient) UpdatePermissions(ctx context.Context, req PasswordPermissionsRequest, opts ...call.Option) (*PasswordPermissions, error) { + wireReq, err := passwordPermissionsRequestToWire(&req) if err != nil { return nil, err } @@ -3076,8 +3150,8 @@ func (c *internalClient) UpdatePermissions(ctx context.Context, req *PasswordPer // Replaces a user's information with the data supplied in request. The // `userName` and `emails` attributes cannot be updated through this API; any // supplied changes to them are ignored (no-op). -func (c *internalClient) UpdateUser(ctx context.Context, req *UpdateUserRequest, opts ...call.Option) error { - wireReq, err := updateUserRequestToWire(req) +func (c *internalClient) UpdateUser(ctx context.Context, req UpdateUserRequest, opts ...call.Option) error { + wireReq, err := updateUserRequestToWire(&req) if err != nil { return err } @@ -3098,7 +3172,11 @@ func (c *internalClient) UpdateUser(ctx context.Context, req *UpdateUserRequest, } pb := pathBuilder{} pb.literal("/api/2.0/preview/scim/v2/Users/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/scim/v1/genhelper.go b/scim/v1/genhelper.go old mode 100755 new mode 100644 index 2984f40..c7006ab --- a/scim/v1/genhelper.go +++ b/scim/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/scim/v1/wire.go b/scim/v1/wire.go old mode 100755 new mode 100644 index e9fc474..0f08fb9 --- a/scim/v1/wire.go +++ b/scim/v1/wire.go @@ -3,10 +3,55 @@ package scim import ( + "bytes" "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type accountComplexValueWire struct { Display *string `json:"display,omitempty"` Primary *bool `json:"primary,omitempty"` @@ -623,8 +668,8 @@ type listAccountGroupsRequestWire struct { Filter *string `json:"filter,omitempty"` Attributes *string `json:"attributes,omitempty"` ExcludedAttributes *string `json:"excludedAttributes,omitempty"` - StartIndex *int64 `json:"startIndex,omitempty"` - Count *int64 `json:"count,omitempty"` + StartIndex *wireInt64 `json:"startIndex,omitempty"` + Count *wireInt64 `json:"count,omitempty"` SortBy *string `json:"sortBy,omitempty"` SortOrder AccountListSort_Order `json:"sortOrder,omitempty"` } @@ -633,13 +678,21 @@ func listAccountGroupsRequestToWire(v *ListAccountGroupsRequest) (*listAccountGr if v == nil { return nil, nil } + startIndexWireValue, err := int64ToWire(v.StartIndex) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListAccountGroupsRequest.StartIndex", err) + } + countWireValue, err := int64ToWire(v.Count) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListAccountGroupsRequest.Count", err) + } return &listAccountGroupsRequestWire{ AccountId: v.AccountId, Filter: v.Filter, Attributes: v.Attributes, ExcludedAttributes: v.ExcludedAttributes, - StartIndex: v.StartIndex, - Count: v.Count, + StartIndex: startIndexWireValue, + Count: countWireValue, SortBy: v.SortBy, SortOrder: v.SortOrder, }, nil @@ -648,7 +701,7 @@ func listAccountGroupsRequestToWire(v *ListAccountGroupsRequest) (*listAccountGr type listAccountGroupsResponseWire struct { ItemsPerPage *int `json:"itemsPerPage,omitempty"` Resources []accountGroupWire `json:"Resources,omitempty"` - StartIndex *int64 `json:"startIndex,omitempty"` + StartIndex *wireInt64 `json:"startIndex,omitempty"` TotalResults *int `json:"totalResults,omitempty"` } @@ -660,22 +713,26 @@ func listAccountGroupsResponseFromWire(w *listAccountGroupsResponseWire) (*ListA if err != nil { return nil, fmt.Errorf("%s: %w", "ListAccountGroupsResponse.Resources", err) } + startIndexPublicValue, err := int64FromWire(w.StartIndex) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListAccountGroupsResponse.StartIndex", err) + } return &ListAccountGroupsResponse{ ItemsPerPage: w.ItemsPerPage, Resources: resourcesPublicValue, - StartIndex: w.StartIndex, + StartIndex: startIndexPublicValue, TotalResults: w.TotalResults, }, nil } type listAccountServicePrincipalsRequestWire struct { Attributes *string `json:"attributes,omitempty"` - Count *int64 `json:"count,omitempty"` + Count *wireInt64 `json:"count,omitempty"` ExcludedAttributes *string `json:"excludedAttributes,omitempty"` Filter *string `json:"filter,omitempty"` SortBy *string `json:"sortBy,omitempty"` SortOrder AccountListSort_Order `json:"sortOrder,omitempty"` - StartIndex *int64 `json:"startIndex,omitempty"` + StartIndex *wireInt64 `json:"startIndex,omitempty"` AccountId *string `json:"account_id,omitempty"` } @@ -683,14 +740,22 @@ func listAccountServicePrincipalsRequestToWire(v *ListAccountServicePrincipalsRe if v == nil { return nil, nil } + countWireValue, err := int64ToWire(v.Count) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListAccountServicePrincipalsRequest.Count", err) + } + startIndexWireValue, err := int64ToWire(v.StartIndex) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListAccountServicePrincipalsRequest.StartIndex", err) + } return &listAccountServicePrincipalsRequestWire{ Attributes: v.Attributes, - Count: v.Count, + Count: countWireValue, ExcludedAttributes: v.ExcludedAttributes, Filter: v.Filter, SortBy: v.SortBy, SortOrder: v.SortOrder, - StartIndex: v.StartIndex, + StartIndex: startIndexWireValue, AccountId: v.AccountId, }, nil } @@ -698,7 +763,7 @@ func listAccountServicePrincipalsRequestToWire(v *ListAccountServicePrincipalsRe type listAccountServicePrincipalsResponseWire struct { ItemsPerPage *int `json:"itemsPerPage,omitempty"` Resources []accountServicePrincipalWire `json:"Resources,omitempty"` - StartIndex *int64 `json:"startIndex,omitempty"` + StartIndex *wireInt64 `json:"startIndex,omitempty"` TotalResults *int `json:"totalResults,omitempty"` } @@ -710,22 +775,26 @@ func listAccountServicePrincipalsResponseFromWire(w *listAccountServicePrincipal if err != nil { return nil, fmt.Errorf("%s: %w", "ListAccountServicePrincipalsResponse.Resources", err) } + startIndexPublicValue, err := int64FromWire(w.StartIndex) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListAccountServicePrincipalsResponse.StartIndex", err) + } return &ListAccountServicePrincipalsResponse{ ItemsPerPage: w.ItemsPerPage, Resources: resourcesPublicValue, - StartIndex: w.StartIndex, + StartIndex: startIndexPublicValue, TotalResults: w.TotalResults, }, nil } type listAccountUsersRequestWire struct { Attributes *string `json:"attributes,omitempty"` - Count *int64 `json:"count,omitempty"` + Count *wireInt64 `json:"count,omitempty"` ExcludedAttributes *string `json:"excludedAttributes,omitempty"` Filter *string `json:"filter,omitempty"` SortBy *string `json:"sortBy,omitempty"` SortOrder AccountListSort_Order `json:"sortOrder,omitempty"` - StartIndex *int64 `json:"startIndex,omitempty"` + StartIndex *wireInt64 `json:"startIndex,omitempty"` AccountId *string `json:"account_id,omitempty"` } @@ -733,14 +802,22 @@ func listAccountUsersRequestToWire(v *ListAccountUsersRequest) (*listAccountUser if v == nil { return nil, nil } + countWireValue, err := int64ToWire(v.Count) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListAccountUsersRequest.Count", err) + } + startIndexWireValue, err := int64ToWire(v.StartIndex) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListAccountUsersRequest.StartIndex", err) + } return &listAccountUsersRequestWire{ Attributes: v.Attributes, - Count: v.Count, + Count: countWireValue, ExcludedAttributes: v.ExcludedAttributes, Filter: v.Filter, SortBy: v.SortBy, SortOrder: v.SortOrder, - StartIndex: v.StartIndex, + StartIndex: startIndexWireValue, AccountId: v.AccountId, }, nil } @@ -748,7 +825,7 @@ func listAccountUsersRequestToWire(v *ListAccountUsersRequest) (*listAccountUser type listAccountUsersResponseWire struct { ItemsPerPage *int `json:"itemsPerPage,omitempty"` Resources []accountUserWire `json:"Resources,omitempty"` - StartIndex *int64 `json:"startIndex,omitempty"` + StartIndex *wireInt64 `json:"startIndex,omitempty"` TotalResults *int `json:"totalResults,omitempty"` } @@ -760,10 +837,14 @@ func listAccountUsersResponseFromWire(w *listAccountUsersResponseWire) (*ListAcc if err != nil { return nil, fmt.Errorf("%s: %w", "ListAccountUsersResponse.Resources", err) } + startIndexPublicValue, err := int64FromWire(w.StartIndex) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListAccountUsersResponse.StartIndex", err) + } return &ListAccountUsersResponse{ ItemsPerPage: w.ItemsPerPage, Resources: resourcesPublicValue, - StartIndex: w.StartIndex, + StartIndex: startIndexPublicValue, TotalResults: w.TotalResults, }, nil } @@ -772,8 +853,8 @@ type listGroupsRequestWire struct { Filter *string `json:"filter,omitempty"` Attributes *string `json:"attributes,omitempty"` ExcludedAttributes *string `json:"excludedAttributes,omitempty"` - StartIndex *int64 `json:"startIndex,omitempty"` - Count *int64 `json:"count,omitempty"` + StartIndex *wireInt64 `json:"startIndex,omitempty"` + Count *wireInt64 `json:"count,omitempty"` SortBy *string `json:"sortBy,omitempty"` SortOrder ListSort_Order `json:"sortOrder,omitempty"` } @@ -782,12 +863,20 @@ func listGroupsRequestToWire(v *ListGroupsRequest) (*listGroupsRequestWire, erro if v == nil { return nil, nil } + startIndexWireValue, err := int64ToWire(v.StartIndex) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListGroupsRequest.StartIndex", err) + } + countWireValue, err := int64ToWire(v.Count) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListGroupsRequest.Count", err) + } return &listGroupsRequestWire{ Filter: v.Filter, Attributes: v.Attributes, ExcludedAttributes: v.ExcludedAttributes, - StartIndex: v.StartIndex, - Count: v.Count, + StartIndex: startIndexWireValue, + Count: countWireValue, SortBy: v.SortBy, SortOrder: v.SortOrder, }, nil @@ -797,7 +886,7 @@ type listGroupsResponseWire struct { ItemsPerPage *int `json:"itemsPerPage,omitempty"` Resources []groupWire `json:"Resources,omitempty"` Schemas []ListResponseSchema `json:"schemas,omitempty"` - StartIndex *int64 `json:"startIndex,omitempty"` + StartIndex *wireInt64 `json:"startIndex,omitempty"` TotalResults *int `json:"totalResults,omitempty"` } @@ -809,11 +898,15 @@ func listGroupsResponseFromWire(w *listGroupsResponseWire) (*ListGroupsResponse, if err != nil { return nil, fmt.Errorf("%s: %w", "ListGroupsResponse.Resources", err) } + startIndexPublicValue, err := int64FromWire(w.StartIndex) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListGroupsResponse.StartIndex", err) + } return &ListGroupsResponse{ ItemsPerPage: w.ItemsPerPage, Resources: resourcesPublicValue, Schemas: w.Schemas, - StartIndex: w.StartIndex, + StartIndex: startIndexPublicValue, TotalResults: w.TotalResults, }, nil } @@ -822,7 +915,7 @@ type listServicePrincipalResponseWire struct { ItemsPerPage *int `json:"itemsPerPage,omitempty"` Resources []servicePrincipalWire `json:"Resources,omitempty"` Schemas []ListResponseSchema `json:"schemas,omitempty"` - StartIndex *int64 `json:"startIndex,omitempty"` + StartIndex *wireInt64 `json:"startIndex,omitempty"` TotalResults *int `json:"totalResults,omitempty"` } @@ -834,62 +927,82 @@ func listServicePrincipalResponseFromWire(w *listServicePrincipalResponseWire) ( if err != nil { return nil, fmt.Errorf("%s: %w", "ListServicePrincipalResponse.Resources", err) } + startIndexPublicValue, err := int64FromWire(w.StartIndex) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListServicePrincipalResponse.StartIndex", err) + } return &ListServicePrincipalResponse{ ItemsPerPage: w.ItemsPerPage, Resources: resourcesPublicValue, Schemas: w.Schemas, - StartIndex: w.StartIndex, + StartIndex: startIndexPublicValue, TotalResults: w.TotalResults, }, nil } type listServicePrincipalsRequestWire struct { Attributes *string `json:"attributes,omitempty"` - Count *int64 `json:"count,omitempty"` + Count *wireInt64 `json:"count,omitempty"` ExcludedAttributes *string `json:"excludedAttributes,omitempty"` Filter *string `json:"filter,omitempty"` SortBy *string `json:"sortBy,omitempty"` SortOrder ListSort_Order `json:"sortOrder,omitempty"` - StartIndex *int64 `json:"startIndex,omitempty"` + StartIndex *wireInt64 `json:"startIndex,omitempty"` } func listServicePrincipalsRequestToWire(v *ListServicePrincipalsRequest) (*listServicePrincipalsRequestWire, error) { if v == nil { return nil, nil } + countWireValue, err := int64ToWire(v.Count) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListServicePrincipalsRequest.Count", err) + } + startIndexWireValue, err := int64ToWire(v.StartIndex) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListServicePrincipalsRequest.StartIndex", err) + } return &listServicePrincipalsRequestWire{ Attributes: v.Attributes, - Count: v.Count, + Count: countWireValue, ExcludedAttributes: v.ExcludedAttributes, Filter: v.Filter, SortBy: v.SortBy, SortOrder: v.SortOrder, - StartIndex: v.StartIndex, + StartIndex: startIndexWireValue, }, nil } type listUsersRequestWire struct { Attributes *string `json:"attributes,omitempty"` - Count *int64 `json:"count,omitempty"` + Count *wireInt64 `json:"count,omitempty"` ExcludedAttributes *string `json:"excludedAttributes,omitempty"` Filter *string `json:"filter,omitempty"` SortBy *string `json:"sortBy,omitempty"` SortOrder ListSort_Order `json:"sortOrder,omitempty"` - StartIndex *int64 `json:"startIndex,omitempty"` + StartIndex *wireInt64 `json:"startIndex,omitempty"` } func listUsersRequestToWire(v *ListUsersRequest) (*listUsersRequestWire, error) { if v == nil { return nil, nil } + countWireValue, err := int64ToWire(v.Count) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListUsersRequest.Count", err) + } + startIndexWireValue, err := int64ToWire(v.StartIndex) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListUsersRequest.StartIndex", err) + } return &listUsersRequestWire{ Attributes: v.Attributes, - Count: v.Count, + Count: countWireValue, ExcludedAttributes: v.ExcludedAttributes, Filter: v.Filter, SortBy: v.SortBy, SortOrder: v.SortOrder, - StartIndex: v.StartIndex, + StartIndex: startIndexWireValue, }, nil } @@ -897,7 +1010,7 @@ type listUsersResponseWire struct { ItemsPerPage *int `json:"itemsPerPage,omitempty"` Resources []userWire `json:"Resources,omitempty"` Schemas []ListResponseSchema `json:"schemas,omitempty"` - StartIndex *int64 `json:"startIndex,omitempty"` + StartIndex *wireInt64 `json:"startIndex,omitempty"` TotalResults *int `json:"totalResults,omitempty"` } @@ -909,11 +1022,15 @@ func listUsersResponseFromWire(w *listUsersResponseWire) (*ListUsersResponse, er if err != nil { return nil, fmt.Errorf("%s: %w", "ListUsersResponse.Resources", err) } + startIndexPublicValue, err := int64FromWire(w.StartIndex) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListUsersResponse.StartIndex", err) + } return &ListUsersResponse{ ItemsPerPage: w.ItemsPerPage, Resources: resourcesPublicValue, Schemas: w.Schemas, - StartIndex: w.StartIndex, + StartIndex: startIndexPublicValue, TotalResults: w.TotalResults, }, nil } diff --git a/secrets/CHANGELOG.md b/secrets/CHANGELOG.md index 6224c04..19f237c 100644 --- a/secrets/CHANGELOG.md +++ b/secrets/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/secrets/go.mod b/secrets/go.mod index 10bbfb0..6ea3bba 100644 --- a/secrets/go.mod +++ b/secrets/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/secrets/internal/version.go b/secrets/internal/version.go index 16a2499..3013537 100644 --- a/secrets/internal/version.go +++ b/secrets/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-secrets" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/secrets/v1/client.go b/secrets/v1/client.go old mode 100755 new mode 100644 index 71e2dcc..c653d9f --- a/secrets/v1/client.go +++ b/secrets/v1/client.go @@ -110,8 +110,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // “CUSTOMER_UNAUTHORIZED“ if normal user attempts to create a scope with name // reserved for databricks internal usage. Throws “UNAUTHENTICATED“ if unable // to verify user access permission on Azure KeyVault -func (c *internalClient) CreateScope(ctx context.Context, req *CreateScopeRequest, opts ...call.Option) (*CreateScopeResponse, error) { - wireReq, err := createScopeRequestToWire(req) +func (c *internalClient) CreateScope(ctx context.Context, req CreateScopeRequest, opts ...call.Option) (*CreateScopeResponse, error) { + wireReq, err := createScopeRequestToWire(&req) if err != nil { return nil, err } @@ -183,8 +183,8 @@ func (c *internalClient) CreateScope(ctx context.Context, req *CreateScopeReques // exists. Throws “PERMISSION_DENIED“ if the user does not have permission to // make this API call. Throws “INVALID_PARAMETER_VALUE“ if the permission or // principal is invalid. -func (c *internalClient) DeleteAcl(ctx context.Context, req *DeleteAclRequest, opts ...call.Option) (*DeleteAclResponse, error) { - wireReq, err := deleteAclRequestToWire(req) +func (c *internalClient) DeleteAcl(ctx context.Context, req DeleteAclRequest, opts ...call.Option) (*DeleteAclResponse, error) { + wireReq, err := deleteAclRequestToWire(&req) if err != nil { return nil, err } @@ -254,8 +254,8 @@ func (c *internalClient) DeleteAcl(ctx context.Context, req *DeleteAclRequest, o // “PERMISSION_DENIED“ if the user does not have permission to make this API // call. Throws “BAD_REQUEST“ if system user attempts to delete internal // secret scope. -func (c *internalClient) DeleteScope(ctx context.Context, req *DeleteScopeRequest, opts ...call.Option) (*DeleteScopeResponse, error) { - wireReq, err := deleteScopeRequestToWire(req) +func (c *internalClient) DeleteScope(ctx context.Context, req DeleteScopeRequest, opts ...call.Option) (*DeleteScopeResponse, error) { + wireReq, err := deleteScopeRequestToWire(&req) if err != nil { return nil, err } @@ -326,8 +326,8 @@ func (c *internalClient) DeleteScope(ctx context.Context, req *DeleteScopeReques // Throws “PERMISSION_DENIED“ if the user does not have permission to make // this API call. Throws “BAD_REQUEST“ if system user attempts to delete an // internal secret, or request is made against Azure KeyVault backed scope. -func (c *internalClient) DeleteSecret(ctx context.Context, req *DeleteSecretRequest, opts ...call.Option) (*DeleteSecretResponse, error) { - wireReq, err := deleteSecretRequestToWire(req) +func (c *internalClient) DeleteSecret(ctx context.Context, req DeleteSecretRequest, opts ...call.Option) (*DeleteSecretResponse, error) { + wireReq, err := deleteSecretRequestToWire(&req) if err != nil { return nil, err } @@ -399,8 +399,8 @@ func (c *internalClient) DeleteSecret(ctx context.Context, req *DeleteSecretRequ // “PERMISSION_DENIED“ if the user does not have permission to make this API // call. Throws “INVALID_PARAMETER_VALUE“ if the permission or principal is // invalid. -func (c *internalClient) GetAcl(ctx context.Context, req *GetAclRequest, opts ...call.Option) (*AclItem, error) { - wireReq, err := getAclRequestToWire(req) +func (c *internalClient) GetAcl(ctx context.Context, req GetAclRequest, opts ...call.Option) (*AclItem, error) { + wireReq, err := getAclRequestToWire(&req) if err != nil { return nil, err } @@ -492,8 +492,8 @@ func (c *internalClient) GetAcl(ctx context.Context, req *GetAclRequest, opts .. // alphanumeric or too long. Throws “PERMISSION_DENIED“ if secret manager // cannot access AKV with 403 error Throws “MALFORMED_REQUEST“ if secret // manager cannot access AKV with any other 4xx error -func (c *internalClient) GetSecret(ctx context.Context, req *GetSecretRequest, opts ...call.Option) (*GetSecretResponse, error) { - wireReq, err := getSecretRequestToWire(req) +func (c *internalClient) GetSecret(ctx context.Context, req GetSecretRequest, opts ...call.Option) (*GetSecretResponse, error) { + wireReq, err := getSecretRequestToWire(&req) if err != nil { return nil, err } @@ -572,8 +572,8 @@ func (c *internalClient) GetSecret(ctx context.Context, req *GetSecretRequest, o // Throws “RESOURCE_DOES_NOT_EXIST“ if no such secret scope exists. Throws // “PERMISSION_DENIED“ if the user does not have permission to make this API // call. -func (c *internalClient) ListAcls(ctx context.Context, req *ListAclsRequest, opts ...call.Option) (*ListAclsResponse, error) { - wireReq, err := listAclsRequestToWire(req) +func (c *internalClient) ListAcls(ctx context.Context, req ListAclsRequest, opts ...call.Option) (*ListAclsResponse, error) { + wireReq, err := listAclsRequestToWire(&req) if err != nil { return nil, err } @@ -646,7 +646,7 @@ func (c *internalClient) ListAcls(ctx context.Context, req *ListAclsRequest, opt // // Throws “PERMISSION_DENIED“ if the user does not have permission to make // this API call. -func (c *internalClient) ListScopes(ctx context.Context, req *ListScopesRequest, opts ...call.Option) (*ListScopesResponse, error) { +func (c *internalClient) ListScopes(ctx context.Context, req ListScopesRequest, opts ...call.Option) (*ListScopesResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -719,8 +719,8 @@ func (c *internalClient) ListScopes(ctx context.Context, req *ListScopesRequest, // Throws “RESOURCE_DOES_NOT_EXIST“ if no such secret scope exists. Throws // “PERMISSION_DENIED“ if the user does not have permission to make this API // call. -func (c *internalClient) ListSecrets(ctx context.Context, req *ListSecretsRequest, opts ...call.Option) (*ListSecretsResponse, error) { - wireReq, err := listSecretsRequestToWire(req) +func (c *internalClient) ListSecrets(ctx context.Context, req ListSecretsRequest, opts ...call.Option) (*ListSecretsResponse, error) { + wireReq, err := listSecretsRequestToWire(&req) if err != nil { return nil, err } @@ -815,8 +815,8 @@ func (c *internalClient) ListSecrets(ctx context.Context, req *ListSecretsReques // Throws “INVALID_PARAMETER_VALUE“ if the permission or principal is invalid. // Throws “PERMISSION_DENIED“ if the user does not have permission to make // this API call. -func (c *internalClient) PutAcl(ctx context.Context, req *PutAclRequest, opts ...call.Option) (*PutAclResponse, error) { - wireReq, err := putAclRequestToWire(req) +func (c *internalClient) PutAcl(ctx context.Context, req PutAclRequest, opts ...call.Option) (*PutAclResponse, error) { + wireReq, err := putAclRequestToWire(&req) if err != nil { return nil, err } @@ -902,8 +902,8 @@ func (c *internalClient) PutAcl(ctx context.Context, req *PutAclRequest, opts .. // make this API call. Throws “MALFORMED_REQUEST“ if request is incorrectly // formatted or conflicting. Throws “BAD_REQUEST“ if request is made against // Azure KeyVault backed scope. -func (c *internalClient) PutSecret(ctx context.Context, req *PutSecretRequest, opts ...call.Option) (*PutSecretResponse, error) { - wireReq, err := putSecretRequestToWire(req) +func (c *internalClient) PutSecret(ctx context.Context, req PutSecretRequest, opts ...call.Option) (*PutSecretResponse, error) { + wireReq, err := putSecretRequestToWire(&req) if err != nil { return nil, err } diff --git a/secrets/v1/wire.go b/secrets/v1/wire.go old mode 100755 new mode 100644 index eb26151..1de6f7d --- a/secrets/v1/wire.go +++ b/secrets/v1/wire.go @@ -3,9 +3,55 @@ package secrets import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type aclItemWire struct { Principal *string `json:"principal,omitempty"` Permission AclPermission `json:"permission,omitempty"` @@ -286,17 +332,21 @@ func putSecretRequestToWire(v *PutSecretRequest) (*putSecretRequestWire, error) } type secretMetadataWire struct { - Key *string `json:"key,omitempty"` - LastUpdatedTimestamp *int64 `json:"last_updated_timestamp,omitempty"` + Key *string `json:"key,omitempty"` + LastUpdatedTimestamp *wireInt64 `json:"last_updated_timestamp,omitempty"` } func secretMetadataFromWire(w *secretMetadataWire) (*SecretMetadata, error) { if w == nil { return nil, nil } + lastUpdatedTimestampPublicValue, err := int64FromWire(w.LastUpdatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SecretMetadata.LastUpdatedTimestamp", err) + } return &SecretMetadata{ Key: w.Key, - LastUpdatedTimestamp: w.LastUpdatedTimestamp, + LastUpdatedTimestamp: lastUpdatedTimestampPublicValue, }, nil } diff --git a/settings/CHANGELOG.md b/settings/CHANGELOG.md index 6224c04..19f237c 100644 --- a/settings/CHANGELOG.md +++ b/settings/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/settings/go.mod b/settings/go.mod index e444738..857e6ad 100644 --- a/settings/go.mod +++ b/settings/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/settings/internal/version.go b/settings/internal/version.go index db7d0f0..a480678 100644 --- a/settings/internal/version.go +++ b/settings/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-settings" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/settings/v2/client.go b/settings/v2/client.go old mode 100755 new mode 100644 index 70247c7..294c49f --- a/settings/v2/client.go +++ b/settings/v2/client.go @@ -78,7 +78,7 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // :method:settingsv2/listaccountsettingsmetadata for list of setting available // via public APIs at account level. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetPublicAccountSetting(ctx context.Context, req *GetPublicAccountSettingRequest, opts ...call.Option) (*Setting, error) { +func (c *internalClient) GetPublicAccountSetting(ctx context.Context, req GetPublicAccountSettingRequest, opts ...call.Option) (*Setting, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -95,7 +95,11 @@ func (c *internalClient) GetPublicAccountSetting(ctx context.Context, req *GetPu pb.literal("/api/2.1/accounts/") pb.singleSegment(accountID) pb.literal("/settings/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -145,7 +149,7 @@ func (c *internalClient) GetPublicAccountSetting(ctx context.Context, req *GetPu // See :method:settingsv2/listaccountuserpreferencesmetadata for list of user // preferences available via public APIs. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetPublicAccountUserPreference(ctx context.Context, req *GetPublicAccountUserPreferenceRequest, opts ...call.Option) (*UserPreference, error) { +func (c *internalClient) GetPublicAccountUserPreference(ctx context.Context, req GetPublicAccountUserPreferenceRequest, opts ...call.Option) (*UserPreference, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -162,9 +166,17 @@ func (c *internalClient) GetPublicAccountUserPreference(ctx context.Context, req pb.literal("/api/2.1/accounts/") pb.singleSegment(accountID) pb.literal("/users/") - pb.singleSegment(*req.UserId) + if req.UserId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.UserId) + } pb.literal("/settings/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -212,7 +224,7 @@ func (c *internalClient) GetPublicAccountUserPreference(ctx context.Context, req // Get a setting value at workspace level. See // :method:settingsv2/listworkspacesettingsmetadata for list of setting // available via public APIs. -func (c *internalClient) GetPublicWorkspaceSetting(ctx context.Context, req *GetPublicWorkspaceSettingRequest, opts ...call.Option) (*Setting, error) { +func (c *internalClient) GetPublicWorkspaceSetting(ctx context.Context, req GetPublicWorkspaceSettingRequest, opts ...call.Option) (*Setting, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -226,7 +238,11 @@ func (c *internalClient) GetPublicWorkspaceSetting(ctx context.Context, req *Get } pb := pathBuilder{} pb.literal("/api/2.1/settings/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -275,8 +291,8 @@ func (c *internalClient) GetPublicWorkspaceSetting(ctx context.Context, req *Get // referenced via GET :method:settingsv2/getpublicaccountsetting and PATCH // :method:settingsv2/patchpublicaccountsetting APIs // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListAccountSettingsMetadata(ctx context.Context, req *ListAccountSettingsMetadataRequest, opts ...call.Option) (*ListAccountSettingsMetadataResponse, error) { - wireReq, err := listAccountSettingsMetadataRequestToWire(req) +func (c *internalClient) ListAccountSettingsMetadata(ctx context.Context, req ListAccountSettingsMetadataRequest, opts ...call.Option) (*ListAccountSettingsMetadataResponse, error) { + wireReq, err := listAccountSettingsMetadataRequestToWire(&req) if err != nil { return nil, err } @@ -351,7 +367,7 @@ func (c *internalClient) ListAccountSettingsMetadata(ctx context.Context, req *L // // For example: // -// for item, err := range c.ListAccountSettingsMetadataIter(ctx, &ListAccountSettingsMetadataRequest{}) { +// for item, err := range c.ListAccountSettingsMetadataIter(ctx, ListAccountSettingsMetadataRequest{}) { // if err != nil { // return err // } @@ -363,16 +379,13 @@ func (c *internalClient) ListAccountSettingsMetadata(ctx context.Context, req *L // // Callers who need custom pagination logic should use // ListAccountSettingsMetadata directly. -func (c *internalClient) ListAccountSettingsMetadataIter(ctx context.Context, req *ListAccountSettingsMetadataRequest, opts ...call.Option) iter.Seq2[*SettingsMetadata, error] { +func (c *internalClient) ListAccountSettingsMetadataIter(ctx context.Context, req ListAccountSettingsMetadataRequest, opts ...call.Option) iter.Seq2[*SettingsMetadata, error] { return func(yield func(*SettingsMetadata, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListAccountSettingsMetadataRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListAccountSettingsMetadata(ctx, &pageReq, opts...) + resp, err := c.ListAccountSettingsMetadata(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -396,8 +409,8 @@ func (c *internalClient) ListAccountSettingsMetadataIter(ctx context.Context, re // :method:settingsv2/getpublicaccountuserpreference and PATCH // :method:settingsv2/patchpublicaccountuserpreference APIs // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListAccountUserPreferencesMetadata(ctx context.Context, req *ListAccountUserPreferencesMetadataRequest, opts ...call.Option) (*ListAccountUserPreferencesMetadataResponse, error) { - wireReq, err := listAccountUserPreferencesMetadataRequestToWire(req) +func (c *internalClient) ListAccountUserPreferencesMetadata(ctx context.Context, req ListAccountUserPreferencesMetadataRequest, opts ...call.Option) (*ListAccountUserPreferencesMetadataResponse, error) { + wireReq, err := listAccountUserPreferencesMetadataRequestToWire(&req) if err != nil { return nil, err } @@ -417,7 +430,11 @@ func (c *internalClient) ListAccountUserPreferencesMetadata(ctx context.Context, pb.literal("/api/2.1/accounts/") pb.singleSegment(accountID) pb.literal("/users/") - pb.singleSegment(*req.UserId) + if req.UserId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.UserId) + } pb.literal("/settings-metadata") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -474,7 +491,7 @@ func (c *internalClient) ListAccountUserPreferencesMetadata(ctx context.Context, // // For example: // -// for item, err := range c.ListAccountUserPreferencesMetadataIter(ctx, &ListAccountUserPreferencesMetadataRequest{}) { +// for item, err := range c.ListAccountUserPreferencesMetadataIter(ctx, ListAccountUserPreferencesMetadataRequest{}) { // if err != nil { // return err // } @@ -486,16 +503,13 @@ func (c *internalClient) ListAccountUserPreferencesMetadata(ctx context.Context, // // Callers who need custom pagination logic should use // ListAccountUserPreferencesMetadata directly. -func (c *internalClient) ListAccountUserPreferencesMetadataIter(ctx context.Context, req *ListAccountUserPreferencesMetadataRequest, opts ...call.Option) iter.Seq2[*SettingsMetadata, error] { +func (c *internalClient) ListAccountUserPreferencesMetadataIter(ctx context.Context, req ListAccountUserPreferencesMetadataRequest, opts ...call.Option) iter.Seq2[*SettingsMetadata, error] { return func(yield func(*SettingsMetadata, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListAccountUserPreferencesMetadataRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListAccountUserPreferencesMetadata(ctx, &pageReq, opts...) + resp, err := c.ListAccountUserPreferencesMetadata(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -516,8 +530,8 @@ func (c *internalClient) ListAccountUserPreferencesMetadataIter(ctx context.Cont // List valid setting keys and metadata. These settings are available to be // referenced via GET :method:settingsv2/getpublicworkspacesetting and PATCH // :method:settingsv2/patchpublicworkspacesetting APIs -func (c *internalClient) ListWorkspaceSettingsMetadata(ctx context.Context, req *ListWorkspaceSettingsMetadataRequest, opts ...call.Option) (*ListWorkspaceSettingsMetadataResponse, error) { - wireReq, err := listWorkspaceSettingsMetadataRequestToWire(req) +func (c *internalClient) ListWorkspaceSettingsMetadata(ctx context.Context, req ListWorkspaceSettingsMetadataRequest, opts ...call.Option) (*ListWorkspaceSettingsMetadataResponse, error) { + wireReq, err := listWorkspaceSettingsMetadataRequestToWire(&req) if err != nil { return nil, err } @@ -587,7 +601,7 @@ func (c *internalClient) ListWorkspaceSettingsMetadata(ctx context.Context, req // // For example: // -// for item, err := range c.ListWorkspaceSettingsMetadataIter(ctx, &ListWorkspaceSettingsMetadataRequest{}) { +// for item, err := range c.ListWorkspaceSettingsMetadataIter(ctx, ListWorkspaceSettingsMetadataRequest{}) { // if err != nil { // return err // } @@ -599,16 +613,13 @@ func (c *internalClient) ListWorkspaceSettingsMetadata(ctx context.Context, req // // Callers who need custom pagination logic should use // ListWorkspaceSettingsMetadata directly. -func (c *internalClient) ListWorkspaceSettingsMetadataIter(ctx context.Context, req *ListWorkspaceSettingsMetadataRequest, opts ...call.Option) iter.Seq2[*SettingsMetadata, error] { +func (c *internalClient) ListWorkspaceSettingsMetadataIter(ctx context.Context, req ListWorkspaceSettingsMetadataRequest, opts ...call.Option) iter.Seq2[*SettingsMetadata, error] { return func(yield func(*SettingsMetadata, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListWorkspaceSettingsMetadataRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListWorkspaceSettingsMetadata(ctx, &pageReq, opts...) + resp, err := c.ListWorkspaceSettingsMetadata(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -634,8 +645,8 @@ func (c *internalClient) ListWorkspaceSettingsMetadataIter(ctx context.Context, // // Note: Page refresh is required for changes to take effect in UI. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) PatchPublicAccountSetting(ctx context.Context, req *PatchPublicAccountSettingRequest, opts ...call.Option) (*Setting, error) { - wireReq, err := patchPublicAccountSettingRequestToWire(req) +func (c *internalClient) PatchPublicAccountSetting(ctx context.Context, req PatchPublicAccountSettingRequest, opts ...call.Option) (*Setting, error) { + wireReq, err := patchPublicAccountSettingRequestToWire(&req) if err != nil { return nil, err } @@ -659,7 +670,11 @@ func (c *internalClient) PatchPublicAccountSetting(ctx context.Context, req *Pat pb.literal("/api/2.1/accounts/") pb.singleSegment(accountID) pb.literal("/settings/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -712,8 +727,8 @@ func (c *internalClient) PatchPublicAccountSetting(ctx context.Context, req *Pat // // Note: Page refresh is required for changes to take effect in UI. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) PatchPublicAccountUserPreference(ctx context.Context, req *PatchPublicAccountUserPreferenceRequest, opts ...call.Option) (*UserPreference, error) { - wireReq, err := patchPublicAccountUserPreferenceRequestToWire(req) +func (c *internalClient) PatchPublicAccountUserPreference(ctx context.Context, req PatchPublicAccountUserPreferenceRequest, opts ...call.Option) (*UserPreference, error) { + wireReq, err := patchPublicAccountUserPreferenceRequestToWire(&req) if err != nil { return nil, err } @@ -737,9 +752,17 @@ func (c *internalClient) PatchPublicAccountUserPreference(ctx context.Context, r pb.literal("/api/2.1/accounts/") pb.singleSegment(accountID) pb.literal("/users/") - pb.singleSegment(*req.UserId) + if req.UserId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.UserId) + } pb.literal("/settings/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -792,8 +815,8 @@ func (c *internalClient) PatchPublicAccountUserPreference(ctx context.Context, r // returned in the :method:settingsv2/listworkspacesettingsmetadata response. // // Note: Page refresh is required for changes to take effect in UI. -func (c *internalClient) PatchPublicWorkspaceSetting(ctx context.Context, req *PatchPublicWorkspaceSettingRequest, opts ...call.Option) (*Setting, error) { - wireReq, err := patchPublicWorkspaceSettingRequestToWire(req) +func (c *internalClient) PatchPublicWorkspaceSetting(ctx context.Context, req PatchPublicWorkspaceSettingRequest, opts ...call.Option) (*Setting, error) { + wireReq, err := patchPublicWorkspaceSettingRequestToWire(&req) if err != nil { return nil, err } @@ -814,7 +837,11 @@ func (c *internalClient) PatchPublicWorkspaceSetting(ctx context.Context, req *P } pb := pathBuilder{} pb.literal("/api/2.1/settings/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/settings/v2/genhelper.go b/settings/v2/genhelper.go old mode 100755 new mode 100644 index 7bfc806..72f517c --- a/settings/v2/genhelper.go +++ b/settings/v2/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/sharing/CHANGELOG.md b/sharing/CHANGELOG.md index 6224c04..19f237c 100644 --- a/sharing/CHANGELOG.md +++ b/sharing/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/sharing/go.mod b/sharing/go.mod index 4b77885..81f075e 100644 --- a/sharing/go.mod +++ b/sharing/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/sharing/internal/version.go b/sharing/internal/version.go index 9b9f307..ebc5ea1 100644 --- a/sharing/internal/version.go +++ b/sharing/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-sharing" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/sharing/v1/client.go b/sharing/v1/client.go old mode 100755 new mode 100644 index c8fa075..5456f47 --- a/sharing/v1/client.go +++ b/sharing/v1/client.go @@ -100,8 +100,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Configuration and usage for User-to-Machine (U2M) applications (e.g., // PowerBI): // https://docs.databricks.com/aws/en/delta-sharing/sharing-over-oidc-u2m -func (c *internalClient) CreateFederationPolicy(ctx context.Context, req *CreateFederationPolicyRequest, opts ...call.Option) (*FederationPolicy, error) { - wireReq, err := createFederationPolicyRequestToWire(req) +func (c *internalClient) CreateFederationPolicy(ctx context.Context, req CreateFederationPolicyRequest, opts ...call.Option) (*FederationPolicy, error) { + wireReq, err := createFederationPolicyRequestToWire(&req) if err != nil { return nil, err } @@ -122,7 +122,11 @@ func (c *internalClient) CreateFederationPolicy(ctx context.Context, req *Create } pb := pathBuilder{} pb.literal("/api/2.0/data-sharing/recipients/") - pb.singleSegment(*req.RecipientName) + if req.RecipientName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.RecipientName) + } pb.literal("/federation-policies") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -171,8 +175,8 @@ func (c *internalClient) CreateFederationPolicy(ctx context.Context, req *Create // Creates a new authentication provider minimally based on a name and // authentication type. The caller must be an admin on the metastore. -func (c *internalClient) CreateProvider(ctx context.Context, req *CreateProviderRequest, opts ...call.Option) (*ProviderInfo, error) { - wireReq, err := createProviderRequestToWire(req) +func (c *internalClient) CreateProvider(ctx context.Context, req CreateProviderRequest, opts ...call.Option) (*ProviderInfo, error) { + wireReq, err := createProviderRequestToWire(&req) if err != nil { return nil, err } @@ -239,8 +243,8 @@ func (c *internalClient) CreateProvider(ctx context.Context, req *CreateProvider // Creates a new recipient with the delta sharing authentication type in the // metastore. The caller must be a metastore admin or have the // **CREATE_RECIPIENT** privilege on the metastore. -func (c *internalClient) CreateRecipient(ctx context.Context, req *CreateRecipientRequest, opts ...call.Option) (*RecipientInfo, error) { - wireReq, err := createRecipientRequestToWire(req) +func (c *internalClient) CreateRecipient(ctx context.Context, req CreateRecipientRequest, opts ...call.Option) (*RecipientInfo, error) { + wireReq, err := createRecipientRequestToWire(&req) if err != nil { return nil, err } @@ -307,8 +311,8 @@ func (c *internalClient) CreateRecipient(ctx context.Context, req *CreateRecipie // Creates a new share for data objects. Data objects can be added after // creation with **update**. The caller must be a metastore admin or have the // **CREATE_SHARE** privilege on the metastore. -func (c *internalClient) CreateShare(ctx context.Context, req *CreateShareRequest, opts ...call.Option) (*ShareInfo, error) { - wireReq, err := createShareRequestToWire(req) +func (c *internalClient) CreateShare(ctx context.Context, req CreateShareRequest, opts ...call.Option) (*ShareInfo, error) { + wireReq, err := createShareRequestToWire(&req) if err != nil { return nil, err } @@ -374,7 +378,7 @@ func (c *internalClient) CreateShare(ctx context.Context, req *CreateShareReques // Deletes an existing federation policy for an OIDC_FEDERATION recipient. The // caller must be the owner of the recipient. -func (c *internalClient) DeleteFederationPolicy(ctx context.Context, req *DeleteFederationPolicyRequest, opts ...call.Option) error { +func (c *internalClient) DeleteFederationPolicy(ctx context.Context, req DeleteFederationPolicyRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -388,9 +392,17 @@ func (c *internalClient) DeleteFederationPolicy(ctx context.Context, req *Delete } pb := pathBuilder{} pb.literal("/api/2.0/data-sharing/recipients/") - pb.singleSegment(*req.RecipientName) + if req.RecipientName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.RecipientName) + } pb.literal("/federation-policies/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -428,7 +440,7 @@ func (c *internalClient) DeleteFederationPolicy(ctx context.Context, req *Delete // Deletes an authentication provider, if the caller is a metastore admin or is // the owner of the provider. -func (c *internalClient) DeleteProvider(ctx context.Context, req *DeleteProviderRequest, opts ...call.Option) (*DeleteProviderResponse, error) { +func (c *internalClient) DeleteProvider(ctx context.Context, req DeleteProviderRequest, opts ...call.Option) (*DeleteProviderResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -442,7 +454,11 @@ func (c *internalClient) DeleteProvider(ctx context.Context, req *DeleteProvider } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/providers/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -483,7 +499,7 @@ func (c *internalClient) DeleteProvider(ctx context.Context, req *DeleteProvider // Deletes the specified recipient from the metastore. The caller must be the // owner of the recipient. -func (c *internalClient) DeleteRecipient(ctx context.Context, req *DeleteRecipientRequest, opts ...call.Option) (*DeleteRecipientResponse, error) { +func (c *internalClient) DeleteRecipient(ctx context.Context, req DeleteRecipientRequest, opts ...call.Option) (*DeleteRecipientResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -497,7 +513,11 @@ func (c *internalClient) DeleteRecipient(ctx context.Context, req *DeleteRecipie } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/recipients/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -538,7 +558,7 @@ func (c *internalClient) DeleteRecipient(ctx context.Context, req *DeleteRecipie // Deletes a data object share from the metastore. The caller must be an owner // of the share. -func (c *internalClient) DeleteShare(ctx context.Context, req *DeleteShareRequest, opts ...call.Option) (*DeleteShareResponse, error) { +func (c *internalClient) DeleteShare(ctx context.Context, req DeleteShareRequest, opts ...call.Option) (*DeleteShareResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -552,7 +572,11 @@ func (c *internalClient) DeleteShare(ctx context.Context, req *DeleteShareReques } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/shares/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -592,7 +616,7 @@ func (c *internalClient) DeleteShare(ctx context.Context, req *DeleteShareReques } // Gets an activation URL for a share. -func (c *internalClient) GetActivationUrlInfo(ctx context.Context, req *GetActivationUrlInfoRequest, opts ...call.Option) (*GetActivationUrlInfoResponse, error) { +func (c *internalClient) GetActivationUrlInfo(ctx context.Context, req GetActivationUrlInfoRequest, opts ...call.Option) (*GetActivationUrlInfoResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -606,7 +630,11 @@ func (c *internalClient) GetActivationUrlInfo(ctx context.Context, req *GetActiv } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/public/data_sharing_activation_info/") - pb.singleSegment(*req.ActivationUrl) + if req.ActivationUrl == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ActivationUrl) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -648,7 +676,7 @@ func (c *internalClient) GetActivationUrlInfo(ctx context.Context, req *GetActiv // Reads an existing federation policy for an OIDC_FEDERATION recipient for // sharing data from to non- recipients. The caller // must have read access to the recipient. -func (c *internalClient) GetFederationPolicy(ctx context.Context, req *GetFederationPolicyRequest, opts ...call.Option) (*FederationPolicy, error) { +func (c *internalClient) GetFederationPolicy(ctx context.Context, req GetFederationPolicyRequest, opts ...call.Option) (*FederationPolicy, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -662,9 +690,17 @@ func (c *internalClient) GetFederationPolicy(ctx context.Context, req *GetFedera } pb := pathBuilder{} pb.literal("/api/2.0/data-sharing/recipients/") - pb.singleSegment(*req.RecipientName) + if req.RecipientName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.RecipientName) + } pb.literal("/federation-policies/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -712,7 +748,7 @@ func (c *internalClient) GetFederationPolicy(ctx context.Context, req *GetFedera // Gets a specific authentication provider. The caller must supply the name of // the provider, and must either be a metastore admin or the owner of the // provider. -func (c *internalClient) GetProvider(ctx context.Context, req *GetProviderRequest, opts ...call.Option) (*ProviderInfo, error) { +func (c *internalClient) GetProvider(ctx context.Context, req GetProviderRequest, opts ...call.Option) (*ProviderInfo, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -726,7 +762,11 @@ func (c *internalClient) GetProvider(ctx context.Context, req *GetProviderReques } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/providers/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -774,7 +814,7 @@ func (c *internalClient) GetProvider(ctx context.Context, req *GetProviderReques // Gets a share recipient from the metastore. The caller must be one of: * A // user with **USE_RECIPIENT** privilege on the metastore * The owner of the // share recipient * A metastore admin -func (c *internalClient) GetRecipient(ctx context.Context, req *GetRecipientRequest, opts ...call.Option) (*RecipientInfo, error) { +func (c *internalClient) GetRecipient(ctx context.Context, req GetRecipientRequest, opts ...call.Option) (*RecipientInfo, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -788,7 +828,11 @@ func (c *internalClient) GetRecipient(ctx context.Context, req *GetRecipientRequ } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/recipients/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -835,8 +879,8 @@ func (c *internalClient) GetRecipient(ctx context.Context, req *GetRecipientRequ // Gets a data object share from the metastore. The caller must have the // USE_SHARE privilege on the metastore or be the owner of the share. -func (c *internalClient) GetShare(ctx context.Context, req *GetShareRequest, opts ...call.Option) (*ShareInfo, error) { - wireReq, err := getShareRequestToWire(req) +func (c *internalClient) GetShare(ctx context.Context, req GetShareRequest, opts ...call.Option) (*ShareInfo, error) { + wireReq, err := getShareRequestToWire(&req) if err != nil { return nil, err } @@ -853,7 +897,11 @@ func (c *internalClient) GetShare(ctx context.Context, req *GetShareRequest, opt } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/shares/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "include_shared_data", wireReq.IncludeSharedData); err != nil { @@ -904,8 +952,8 @@ func (c *internalClient) GetShare(ctx context.Context, req *GetShareRequest, opt // Lists federation policies for an OIDC_FEDERATION recipient for sharing data // from to non- recipients. The caller must have read // access to the recipient. -func (c *internalClient) ListFederationPolicies(ctx context.Context, req *ListFederationPoliciesRequest, opts ...call.Option) (*ListFederationPoliciesResponse, error) { - wireReq, err := listFederationPoliciesRequestToWire(req) +func (c *internalClient) ListFederationPolicies(ctx context.Context, req ListFederationPoliciesRequest, opts ...call.Option) (*ListFederationPoliciesResponse, error) { + wireReq, err := listFederationPoliciesRequestToWire(&req) if err != nil { return nil, err } @@ -922,7 +970,11 @@ func (c *internalClient) ListFederationPolicies(ctx context.Context, req *ListFe } pb := pathBuilder{} pb.literal("/api/2.0/data-sharing/recipients/") - pb.singleSegment(*req.RecipientName) + if req.RecipientName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.RecipientName) + } pb.literal("/federation-policies") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -979,7 +1031,7 @@ func (c *internalClient) ListFederationPolicies(ctx context.Context, req *ListFe // // For example: // -// for item, err := range c.ListFederationPoliciesIter(ctx, &ListFederationPoliciesRequest{}) { +// for item, err := range c.ListFederationPoliciesIter(ctx, ListFederationPoliciesRequest{}) { // if err != nil { // return err // } @@ -991,16 +1043,13 @@ func (c *internalClient) ListFederationPolicies(ctx context.Context, req *ListFe // // Callers who need custom pagination logic should use // ListFederationPolicies directly. -func (c *internalClient) ListFederationPoliciesIter(ctx context.Context, req *ListFederationPoliciesRequest, opts ...call.Option) iter.Seq2[*FederationPolicy, error] { +func (c *internalClient) ListFederationPoliciesIter(ctx context.Context, req ListFederationPoliciesRequest, opts ...call.Option) iter.Seq2[*FederationPolicy, error] { return func(yield func(*FederationPolicy, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListFederationPoliciesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListFederationPolicies(ctx, &pageReq, opts...) + resp, err := c.ListFederationPolicies(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1020,8 +1069,8 @@ func (c *internalClient) ListFederationPoliciesIter(ctx context.Context, req *Li // Get arrays of assets associated with a specified provider's share. The caller // is the recipient of the share. -func (c *internalClient) ListProviderShareAssets(ctx context.Context, req *ListProviderShareAssetsRequest, opts ...call.Option) (*ListProviderShareAssetsResponse, error) { - wireReq, err := listProviderShareAssetsRequestToWire(req) +func (c *internalClient) ListProviderShareAssets(ctx context.Context, req ListProviderShareAssetsRequest, opts ...call.Option) (*ListProviderShareAssetsResponse, error) { + wireReq, err := listProviderShareAssetsRequestToWire(&req) if err != nil { return nil, err } @@ -1038,9 +1087,17 @@ func (c *internalClient) ListProviderShareAssets(ctx context.Context, req *ListP } pb := pathBuilder{} pb.literal("/api/2.1/data-sharing/providers/") - pb.singleSegment(*req.ProviderNameArg) + if req.ProviderNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ProviderNameArg) + } pb.literal("/shares/") - pb.singleSegment(*req.ShareNameArg) + if req.ShareNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ShareNameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "table_max_results", wireReq.TableMaxResults); err != nil { @@ -1099,8 +1156,8 @@ func (c *internalClient) ListProviderShareAssets(ctx context.Context, req *ListP // Gets an array of a specified provider's shares within the metastore where: * // the caller is a metastore admin, or * the caller is the owner. -func (c *internalClient) ListProviderShares(ctx context.Context, req *ListProviderSharesRequest, opts ...call.Option) (*ListProviderSharesResponse, error) { - wireReq, err := listProviderSharesRequestToWire(req) +func (c *internalClient) ListProviderShares(ctx context.Context, req ListProviderSharesRequest, opts ...call.Option) (*ListProviderSharesResponse, error) { + wireReq, err := listProviderSharesRequestToWire(&req) if err != nil { return nil, err } @@ -1117,7 +1174,11 @@ func (c *internalClient) ListProviderShares(ctx context.Context, req *ListProvid } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/providers/") - pb.singleSegment(*req.ProviderNameArg) + if req.ProviderNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ProviderNameArg) + } pb.literal("/shares") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1174,7 +1235,7 @@ func (c *internalClient) ListProviderShares(ctx context.Context, req *ListProvid // // For example: // -// for item, err := range c.ListProviderSharesIter(ctx, &ListProviderSharesRequest{}) { +// for item, err := range c.ListProviderSharesIter(ctx, ListProviderSharesRequest{}) { // if err != nil { // return err // } @@ -1186,16 +1247,13 @@ func (c *internalClient) ListProviderShares(ctx context.Context, req *ListProvid // // Callers who need custom pagination logic should use // ListProviderShares directly. -func (c *internalClient) ListProviderSharesIter(ctx context.Context, req *ListProviderSharesRequest, opts ...call.Option) iter.Seq2[*ProviderShare, error] { +func (c *internalClient) ListProviderSharesIter(ctx context.Context, req ListProviderSharesRequest, opts ...call.Option) iter.Seq2[*ProviderShare, error] { return func(yield func(*ProviderShare, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListProviderSharesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListProviderShares(ctx, &pageReq, opts...) + resp, err := c.ListProviderShares(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1219,8 +1277,8 @@ func (c *internalClient) ListProviderSharesIter(ctx context.Context, req *ListPr // which the caller does not have the **USE_PROVIDER** privilege are not // included in the response. There is no guarantee of a specific ordering of the // elements in the array. -func (c *internalClient) ListProviders(ctx context.Context, req *ListProvidersRequest, opts ...call.Option) (*ListProvidersResponse, error) { - wireReq, err := listProvidersRequestToWire(req) +func (c *internalClient) ListProviders(ctx context.Context, req ListProvidersRequest, opts ...call.Option) (*ListProvidersResponse, error) { + wireReq, err := listProvidersRequestToWire(&req) if err != nil { return nil, err } @@ -1293,7 +1351,7 @@ func (c *internalClient) ListProviders(ctx context.Context, req *ListProvidersRe // // For example: // -// for item, err := range c.ListProvidersIter(ctx, &ListProvidersRequest{}) { +// for item, err := range c.ListProvidersIter(ctx, ListProvidersRequest{}) { // if err != nil { // return err // } @@ -1305,16 +1363,13 @@ func (c *internalClient) ListProviders(ctx context.Context, req *ListProvidersRe // // Callers who need custom pagination logic should use // ListProviders directly. -func (c *internalClient) ListProvidersIter(ctx context.Context, req *ListProvidersRequest, opts ...call.Option) iter.Seq2[*ProviderInfo, error] { +func (c *internalClient) ListProvidersIter(ctx context.Context, req ListProvidersRequest, opts ...call.Option) iter.Seq2[*ProviderInfo, error] { return func(yield func(*ProviderInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListProvidersRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListProviders(ctx, &pageReq, opts...) + resp, err := c.ListProviders(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1335,8 +1390,8 @@ func (c *internalClient) ListProvidersIter(ctx context.Context, req *ListProvide // Gets the share permissions for the specified Recipient. The caller must have // the **USE_RECIPIENT** privilege on the metastore or be the owner of the // Recipient. -func (c *internalClient) ListRecipientSharePermissions(ctx context.Context, req *ListRecipientSharePermissionsRequest, opts ...call.Option) (*GetRecipientSharePermissionsResponse, error) { - wireReq, err := listRecipientSharePermissionsRequestToWire(req) +func (c *internalClient) ListRecipientSharePermissions(ctx context.Context, req ListRecipientSharePermissionsRequest, opts ...call.Option) (*GetRecipientSharePermissionsResponse, error) { + wireReq, err := listRecipientSharePermissionsRequestToWire(&req) if err != nil { return nil, err } @@ -1353,7 +1408,11 @@ func (c *internalClient) ListRecipientSharePermissions(ctx context.Context, req } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/recipients/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/share-permissions") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1408,8 +1467,8 @@ func (c *internalClient) ListRecipientSharePermissions(ctx context.Context, req // Gets an array of all share recipients within the current metastore where: * // the caller is a metastore admin, or * the caller is the owner. There is no // guarantee of a specific ordering of the elements in the array. -func (c *internalClient) ListRecipients(ctx context.Context, req *ListRecipientsRequest, opts ...call.Option) (*ListRecipientsResponse, error) { - wireReq, err := listRecipientsRequestToWire(req) +func (c *internalClient) ListRecipients(ctx context.Context, req ListRecipientsRequest, opts ...call.Option) (*ListRecipientsResponse, error) { + wireReq, err := listRecipientsRequestToWire(&req) if err != nil { return nil, err } @@ -1482,7 +1541,7 @@ func (c *internalClient) ListRecipients(ctx context.Context, req *ListRecipients // // For example: // -// for item, err := range c.ListRecipientsIter(ctx, &ListRecipientsRequest{}) { +// for item, err := range c.ListRecipientsIter(ctx, ListRecipientsRequest{}) { // if err != nil { // return err // } @@ -1494,16 +1553,13 @@ func (c *internalClient) ListRecipients(ctx context.Context, req *ListRecipients // // Callers who need custom pagination logic should use // ListRecipients directly. -func (c *internalClient) ListRecipientsIter(ctx context.Context, req *ListRecipientsRequest, opts ...call.Option) iter.Seq2[*RecipientInfo, error] { +func (c *internalClient) ListRecipientsIter(ctx context.Context, req ListRecipientsRequest, opts ...call.Option) iter.Seq2[*RecipientInfo, error] { return func(yield func(*RecipientInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListRecipientsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListRecipients(ctx, &pageReq, opts...) + resp, err := c.ListRecipients(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1523,8 +1579,8 @@ func (c *internalClient) ListRecipientsIter(ctx context.Context, req *ListRecipi // Gets the permissions for a data share from the metastore. The caller must // have the USE_SHARE privilege on the metastore or be the owner of the share. -func (c *internalClient) ListSharePermissions(ctx context.Context, req *ListSharePermissionsRequest, opts ...call.Option) (*GetSharePermissionsResponse, error) { - wireReq, err := listSharePermissionsRequestToWire(req) +func (c *internalClient) ListSharePermissions(ctx context.Context, req ListSharePermissionsRequest, opts ...call.Option) (*GetSharePermissionsResponse, error) { + wireReq, err := listSharePermissionsRequestToWire(&req) if err != nil { return nil, err } @@ -1541,7 +1597,11 @@ func (c *internalClient) ListSharePermissions(ctx context.Context, req *ListShar } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/shares/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/permissions") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1597,8 +1657,8 @@ func (c *internalClient) ListSharePermissions(ctx context.Context, req *ListShar // USE_SHARE privilege on the metastore, all shares are returned. Otherwise, // only shares owned by the caller are returned. There is no guarantee of a // specific ordering of the elements in the array. -func (c *internalClient) ListShares(ctx context.Context, req *ListSharesRequest, opts ...call.Option) (*ListSharesResponse, error) { - wireReq, err := listSharesRequestToWire(req) +func (c *internalClient) ListShares(ctx context.Context, req ListSharesRequest, opts ...call.Option) (*ListSharesResponse, error) { + wireReq, err := listSharesRequestToWire(&req) if err != nil { return nil, err } @@ -1668,7 +1728,7 @@ func (c *internalClient) ListShares(ctx context.Context, req *ListSharesRequest, // // For example: // -// for item, err := range c.ListSharesIter(ctx, &ListSharesRequest{}) { +// for item, err := range c.ListSharesIter(ctx, ListSharesRequest{}) { // if err != nil { // return err // } @@ -1680,16 +1740,13 @@ func (c *internalClient) ListShares(ctx context.Context, req *ListSharesRequest, // // Callers who need custom pagination logic should use // ListShares directly. -func (c *internalClient) ListSharesIter(ctx context.Context, req *ListSharesRequest, opts ...call.Option) iter.Seq2[*ShareInfo, error] { +func (c *internalClient) ListSharesIter(ctx context.Context, req ListSharesRequest, opts ...call.Option) iter.Seq2[*ShareInfo, error] { return func(yield func(*ShareInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListSharesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListShares(ctx, &pageReq, opts...) + resp, err := c.ListShares(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1709,7 +1766,7 @@ func (c *internalClient) ListSharesIter(ctx context.Context, req *ListSharesRequ // Retrieve access token with an activation url. This is a public API without // any authentication. -func (c *internalClient) RetrieveAccessToken(ctx context.Context, req *RetrieveTokenRequest, opts ...call.Option) (*RetrieveTokenResponse, error) { +func (c *internalClient) RetrieveAccessToken(ctx context.Context, req RetrieveTokenRequest, opts ...call.Option) (*RetrieveTokenResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1723,7 +1780,11 @@ func (c *internalClient) RetrieveAccessToken(ctx context.Context, req *RetrieveT } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/public/data_sharing_activation/") - pb.singleSegment(*req.ActivationUrl) + if req.ActivationUrl == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ActivationUrl) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1770,8 +1831,8 @@ func (c *internalClient) RetrieveAccessToken(ctx context.Context, req *RetrieveT // Refreshes the specified recipient's delta sharing authentication token with // the provided token info. The caller must be the owner of the recipient. -func (c *internalClient) RotateRecipientToken(ctx context.Context, req *RotateRecipientTokenRequest, opts ...call.Option) (*RecipientInfo, error) { - wireReq, err := rotateRecipientTokenRequestToWire(req) +func (c *internalClient) RotateRecipientToken(ctx context.Context, req RotateRecipientTokenRequest, opts ...call.Option) (*RecipientInfo, error) { + wireReq, err := rotateRecipientTokenRequestToWire(&req) if err != nil { return nil, err } @@ -1792,7 +1853,11 @@ func (c *internalClient) RotateRecipientToken(ctx context.Context, req *RotateRe } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/recipients/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/rotate-token") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1843,8 +1908,8 @@ func (c *internalClient) RotateRecipientToken(ctx context.Context, req *RotateRe // metastore admin or is the owner of the provider. If the update changes the // provider name, the caller must be both a metastore admin and the owner of the // provider. -func (c *internalClient) UpdateProvider(ctx context.Context, req *UpdateProviderRequest, opts ...call.Option) (*ProviderInfo, error) { - wireReq, err := updateProviderRequestToWire(req) +func (c *internalClient) UpdateProvider(ctx context.Context, req UpdateProviderRequest, opts ...call.Option) (*ProviderInfo, error) { + wireReq, err := updateProviderRequestToWire(&req) if err != nil { return nil, err } @@ -1865,7 +1930,11 @@ func (c *internalClient) UpdateProvider(ctx context.Context, req *UpdateProvider } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/providers/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1915,8 +1984,8 @@ func (c *internalClient) UpdateProvider(ctx context.Context, req *UpdateProvider // metastore admin or the owner of the recipient. If the recipient name will be // updated, the user must be both a metastore admin and the owner of the // recipient. -func (c *internalClient) UpdateRecipient(ctx context.Context, req *UpdateRecipientRequest, opts ...call.Option) (*RecipientInfo, error) { - wireReq, err := updateRecipientRequestToWire(req) +func (c *internalClient) UpdateRecipient(ctx context.Context, req UpdateRecipientRequest, opts ...call.Option) (*RecipientInfo, error) { + wireReq, err := updateRecipientRequestToWire(&req) if err != nil { return nil, err } @@ -1937,7 +2006,11 @@ func (c *internalClient) UpdateRecipient(ctx context.Context, req *UpdateRecipie } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/recipients/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1995,8 +2068,8 @@ func (c *internalClient) UpdateRecipient(ctx context.Context, req *UpdateRecipie // maintained indefinitely for recipients to be able to access the table. // Typically, you should use a group as the share owner. Table removals through // **update** do not require additional privileges. -func (c *internalClient) UpdateShare(ctx context.Context, req *UpdateShareRequest, opts ...call.Option) (*ShareInfo, error) { - wireReq, err := updateShareRequestToWire(req) +func (c *internalClient) UpdateShare(ctx context.Context, req UpdateShareRequest, opts ...call.Option) (*ShareInfo, error) { + wireReq, err := updateShareRequestToWire(&req) if err != nil { return nil, err } @@ -2017,7 +2090,11 @@ func (c *internalClient) UpdateShare(ctx context.Context, req *UpdateShareReques } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/shares/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -2069,8 +2146,8 @@ func (c *internalClient) UpdateShare(ctx context.Context, req *UpdateShareReques // // For new recipient grants, the user must also be the owner of the recipients. // recipient revocations do not require additional privileges. -func (c *internalClient) UpdateSharePermissions(ctx context.Context, req *UpdateSharePermissionsRequest, opts ...call.Option) (*UpdateSharePermissionsResponse, error) { - wireReq, err := updateSharePermissionsRequestToWire(req) +func (c *internalClient) UpdateSharePermissions(ctx context.Context, req UpdateSharePermissionsRequest, opts ...call.Option) (*UpdateSharePermissionsResponse, error) { + wireReq, err := updateSharePermissionsRequestToWire(&req) if err != nil { return nil, err } @@ -2091,7 +2168,11 @@ func (c *internalClient) UpdateSharePermissions(ctx context.Context, req *Update } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/shares/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/permissions") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} diff --git a/sharing/v1/genhelper.go b/sharing/v1/genhelper.go old mode 100755 new mode 100644 index c171086..3b19391 --- a/sharing/v1/genhelper.go +++ b/sharing/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/sharing/v1/wire.go b/sharing/v1/wire.go old mode 100755 new mode 100644 index 4aeee5d..4a61ed3 --- a/sharing/v1/wire.go +++ b/sharing/v1/wire.go @@ -3,11 +3,57 @@ package sharing import ( + "bytes" + "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type createFederationPolicyRequestWire struct { RecipientName *string `json:"recipient_name,omitempty"` Policy *federationPolicyWire `json:"policy,omitempty"` @@ -34,9 +80,9 @@ type createProviderRequestWire struct { Comment *string `json:"comment,omitempty"` Owner *string `json:"owner,omitempty"` RecipientProfile *recipientProfileWire `json:"recipient_profile,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` Cloud *string `json:"cloud,omitempty"` Region *string `json:"region,omitempty"` @@ -52,6 +98,14 @@ func createProviderRequestToWire(v *CreateProviderRequest) (*createProviderReque if err != nil { return nil, fmt.Errorf("%s: %w", "CreateProviderRequest.RecipientProfile", err) } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateProviderRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateProviderRequest.UpdatedAt", err) + } return &createProviderRequestWire{ Name: v.Name, AuthenticationType: v.AuthenticationType, @@ -59,9 +113,9 @@ func createProviderRequestToWire(v *CreateProviderRequest) (*createProviderReque Comment: v.Comment, Owner: v.Owner, RecipientProfile: recipientProfileWireValue, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, Cloud: v.Cloud, Region: v.Region, @@ -79,13 +133,13 @@ type createRecipientRequestWire struct { Comment *string `json:"comment,omitempty"` IpAccessList *ipAccessListWire `json:"ip_access_list,omitempty"` PropertiesKvpairs *propertiesKvPairsWire `json:"properties_kvpairs,omitempty"` - ExpirationTime *int64 `json:"expiration_time,omitempty"` + ExpirationTime *wireInt64 `json:"expiration_time,omitempty"` ActivationUrl *string `json:"activation_url,omitempty"` Activated *bool `json:"activated,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` Tokens []recipientTokenInfoWire `json:"tokens,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` Cloud *string `json:"cloud,omitempty"` Region *string `json:"region,omitempty"` @@ -105,10 +159,22 @@ func createRecipientRequestToWire(v *CreateRecipientRequest) (*createRecipientRe if err != nil { return nil, fmt.Errorf("%s: %w", "CreateRecipientRequest.PropertiesKvpairs", err) } + expirationTimeWireValue, err := int64ToWire(v.ExpirationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateRecipientRequest.ExpirationTime", err) + } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateRecipientRequest.CreatedAt", err) + } tokensWireValue, err := convertSlice(v.Tokens, recipientTokenInfoToWire) if err != nil { return nil, fmt.Errorf("%s: %w", "CreateRecipientRequest.Tokens", err) } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateRecipientRequest.UpdatedAt", err) + } return &createRecipientRequestWire{ Name: v.Name, AuthenticationType: v.AuthenticationType, @@ -118,13 +184,13 @@ func createRecipientRequestToWire(v *CreateRecipientRequest) (*createRecipientRe Comment: v.Comment, IpAccessList: ipAccessListWireValue, PropertiesKvpairs: propertiesKvpairsWireValue, - ExpirationTime: v.ExpirationTime, + ExpirationTime: expirationTimeWireValue, ActivationUrl: v.ActivationUrl, Activated: v.Activated, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, Tokens: tokensWireValue, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, Cloud: v.Cloud, Region: v.Region, @@ -139,9 +205,9 @@ type createShareRequestWire struct { Comment *string `json:"comment,omitempty"` StorageRoot *string `json:"storage_root,omitempty"` Objects []sharedDataObjectWire `json:"objects,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` StorageLocation *string `json:"storage_location,omitempty"` } @@ -154,15 +220,23 @@ func createShareRequestToWire(v *CreateShareRequest) (*createShareRequestWire, e if err != nil { return nil, fmt.Errorf("%s: %w", "CreateShareRequest.Objects", err) } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateShareRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateShareRequest.UpdatedAt", err) + } return &createShareRequestWire{ Name: v.Name, Owner: v.Owner, Comment: v.Comment, StorageRoot: v.StorageRoot, Objects: objectsWireValue, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, StorageLocation: v.StorageLocation, }, nil @@ -948,9 +1022,9 @@ type providerInfoWire struct { Comment *string `json:"comment,omitempty"` Owner *string `json:"owner,omitempty"` RecipientProfile *recipientProfileWire `json:"recipient_profile,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` Cloud *string `json:"cloud,omitempty"` Region *string `json:"region,omitempty"` @@ -966,6 +1040,14 @@ func providerInfoFromWire(w *providerInfoWire) (*ProviderInfo, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "ProviderInfo.RecipientProfile", err) } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ProviderInfo.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ProviderInfo.UpdatedAt", err) + } return &ProviderInfo{ Name: w.Name, AuthenticationType: w.AuthenticationType, @@ -973,9 +1055,9 @@ func providerInfoFromWire(w *providerInfoWire) (*ProviderInfo, error) { Comment: w.Comment, Owner: w.Owner, RecipientProfile: recipientProfilePublicValue, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, Cloud: w.Cloud, Region: w.Region, @@ -1006,13 +1088,13 @@ type recipientInfoWire struct { Comment *string `json:"comment,omitempty"` IpAccessList *ipAccessListWire `json:"ip_access_list,omitempty"` PropertiesKvpairs *propertiesKvPairsWire `json:"properties_kvpairs,omitempty"` - ExpirationTime *int64 `json:"expiration_time,omitempty"` + ExpirationTime *wireInt64 `json:"expiration_time,omitempty"` ActivationUrl *string `json:"activation_url,omitempty"` Activated *bool `json:"activated,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` Tokens []recipientTokenInfoWire `json:"tokens,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` Cloud *string `json:"cloud,omitempty"` Region *string `json:"region,omitempty"` @@ -1032,10 +1114,22 @@ func recipientInfoFromWire(w *recipientInfoWire) (*RecipientInfo, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "RecipientInfo.PropertiesKvpairs", err) } + expirationTimePublicValue, err := int64FromWire(w.ExpirationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RecipientInfo.ExpirationTime", err) + } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RecipientInfo.CreatedAt", err) + } tokensPublicValue, err := convertSlice(w.Tokens, recipientTokenInfoFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "RecipientInfo.Tokens", err) } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RecipientInfo.UpdatedAt", err) + } return &RecipientInfo{ Name: w.Name, AuthenticationType: w.AuthenticationType, @@ -1045,13 +1139,13 @@ func recipientInfoFromWire(w *recipientInfoWire) (*RecipientInfo, error) { Comment: w.Comment, IpAccessList: ipAccessListPublicValue, PropertiesKvpairs: propertiesKvpairsPublicValue, - ExpirationTime: w.ExpirationTime, + ExpirationTime: expirationTimePublicValue, ActivationUrl: w.ActivationUrl, Activated: w.Activated, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, Tokens: tokensPublicValue, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, Cloud: w.Cloud, Region: w.Region, @@ -1089,26 +1183,38 @@ func recipientProfileFromWire(w *recipientProfileWire) (*RecipientProfile, error } type recipientTokenInfoWire struct { - Id *string `json:"id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` - CreatedBy *string `json:"created_by,omitempty"` - ActivationUrl *string `json:"activation_url,omitempty"` - ExpirationTime *int64 `json:"expiration_time,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` - UpdatedBy *string `json:"updated_by,omitempty"` + Id *string `json:"id,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` + CreatedBy *string `json:"created_by,omitempty"` + ActivationUrl *string `json:"activation_url,omitempty"` + ExpirationTime *wireInt64 `json:"expiration_time,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` + UpdatedBy *string `json:"updated_by,omitempty"` } func recipientTokenInfoToWire(v *RecipientTokenInfo) (*recipientTokenInfoWire, error) { if v == nil { return nil, nil } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RecipientTokenInfo.CreatedAt", err) + } + expirationTimeWireValue, err := int64ToWire(v.ExpirationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RecipientTokenInfo.ExpirationTime", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RecipientTokenInfo.UpdatedAt", err) + } return &recipientTokenInfoWire{ Id: v.Id, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, ActivationUrl: v.ActivationUrl, - ExpirationTime: v.ExpirationTime, - UpdatedAt: v.UpdatedAt, + ExpirationTime: expirationTimeWireValue, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, }, nil } @@ -1117,29 +1223,45 @@ func recipientTokenInfoFromWire(w *recipientTokenInfoWire) (*RecipientTokenInfo, if w == nil { return nil, nil } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RecipientTokenInfo.CreatedAt", err) + } + expirationTimePublicValue, err := int64FromWire(w.ExpirationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RecipientTokenInfo.ExpirationTime", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RecipientTokenInfo.UpdatedAt", err) + } return &RecipientTokenInfo{ Id: w.Id, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, ActivationUrl: w.ActivationUrl, - ExpirationTime: w.ExpirationTime, - UpdatedAt: w.UpdatedAt, + ExpirationTime: expirationTimePublicValue, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, }, nil } type registeredModelAliasWire struct { - AliasName *string `json:"alias_name,omitempty"` - VersionNum *int64 `json:"version_num,omitempty"` + AliasName *string `json:"alias_name,omitempty"` + VersionNum *wireInt64 `json:"version_num,omitempty"` } func registeredModelAliasFromWire(w *registeredModelAliasWire) (*RegisteredModelAlias, error) { if w == nil { return nil, nil } + versionNumPublicValue, err := int64FromWire(w.VersionNum) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RegisteredModelAlias.VersionNum", err) + } return &RegisteredModelAlias{ AliasName: w.AliasName, - VersionNum: w.VersionNum, + VersionNum: versionNumPublicValue, }, nil } @@ -1163,17 +1285,21 @@ func retrieveTokenResponseFromWire(w *retrieveTokenResponseWire) (*RetrieveToken } type rotateRecipientTokenRequestWire struct { - Name *string `json:"name,omitempty"` - ExistingTokenExpireInSeconds *int64 `json:"existing_token_expire_in_seconds,omitempty"` + Name *string `json:"name,omitempty"` + ExistingTokenExpireInSeconds *wireInt64 `json:"existing_token_expire_in_seconds,omitempty"` } func rotateRecipientTokenRequestToWire(v *RotateRecipientTokenRequest) (*rotateRecipientTokenRequestWire, error) { if v == nil { return nil, nil } + existingTokenExpireInSecondsWireValue, err := int64ToWire(v.ExistingTokenExpireInSeconds) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RotateRecipientTokenRequest.ExistingTokenExpireInSeconds", err) + } return &rotateRecipientTokenRequestWire{ Name: v.Name, - ExistingTokenExpireInSeconds: v.ExistingTokenExpireInSeconds, + ExistingTokenExpireInSeconds: existingTokenExpireInSecondsWireValue, }, nil } @@ -1198,9 +1324,9 @@ type shareInfoWire struct { Comment *string `json:"comment,omitempty"` StorageRoot *string `json:"storage_root,omitempty"` Objects []sharedDataObjectWire `json:"objects,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` StorageLocation *string `json:"storage_location,omitempty"` } @@ -1213,15 +1339,23 @@ func shareInfoFromWire(w *shareInfoWire) (*ShareInfo, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "ShareInfo.Objects", err) } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ShareInfo.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ShareInfo.UpdatedAt", err) + } return &ShareInfo{ Name: w.Name, Owner: w.Owner, Comment: w.Comment, StorageRoot: w.StorageRoot, Objects: objectsPublicValue, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, StorageLocation: w.StorageLocation, }, nil @@ -1249,13 +1383,13 @@ func shareToPrivilegeAssignmentFromWire(w *shareToPrivilegeAssignmentWire) (*Sha type sharedDataObjectWire struct { Name *string `json:"name,omitempty"` DataObjectType *string `json:"data_object_type,omitempty"` - AddedAt *int64 `json:"added_at,omitempty"` + AddedAt *wireInt64 `json:"added_at,omitempty"` AddedBy *string `json:"added_by,omitempty"` Comment *string `json:"comment,omitempty"` SharedAs *string `json:"shared_as,omitempty"` CdfEnabled *bool `json:"cdf_enabled,omitempty"` HistoryDataSharingStatus SharedDataObject_HistoryDataSharingStatus_Enum `json:"history_data_sharing_status,omitempty"` - StartVersion *int64 `json:"start_version,omitempty"` + StartVersion *wireInt64 `json:"start_version,omitempty"` Status SharedDataObject_Status_Enum `json:"status,omitempty"` Content *string `json:"content,omitempty"` StringSharedAs *string `json:"string_shared_as,omitempty"` @@ -1266,6 +1400,14 @@ func sharedDataObjectToWire(v *SharedDataObject) (*sharedDataObjectWire, error) if v == nil { return nil, nil } + addedAtWireValue, err := int64ToWire(v.AddedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SharedDataObject.AddedAt", err) + } + startVersionWireValue, err := int64ToWire(v.StartVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SharedDataObject.StartVersion", err) + } partitionsWireValue, err := convertSlice(v.Partitions, partitionSpecification_PartitionToWire) if err != nil { return nil, fmt.Errorf("%s: %w", "SharedDataObject.Partitions", err) @@ -1273,13 +1415,13 @@ func sharedDataObjectToWire(v *SharedDataObject) (*sharedDataObjectWire, error) return &sharedDataObjectWire{ Name: v.Name, DataObjectType: v.DataObjectType, - AddedAt: v.AddedAt, + AddedAt: addedAtWireValue, AddedBy: v.AddedBy, Comment: v.Comment, SharedAs: v.SharedAs, CdfEnabled: v.CdfEnabled, HistoryDataSharingStatus: v.HistoryDataSharingStatus, - StartVersion: v.StartVersion, + StartVersion: startVersionWireValue, Status: v.Status, Content: v.Content, StringSharedAs: v.StringSharedAs, @@ -1291,6 +1433,14 @@ func sharedDataObjectFromWire(w *sharedDataObjectWire) (*SharedDataObject, error if w == nil { return nil, nil } + addedAtPublicValue, err := int64FromWire(w.AddedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SharedDataObject.AddedAt", err) + } + startVersionPublicValue, err := int64FromWire(w.StartVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SharedDataObject.StartVersion", err) + } partitionsPublicValue, err := convertSlice(w.Partitions, partitionSpecification_PartitionFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "SharedDataObject.Partitions", err) @@ -1298,13 +1448,13 @@ func sharedDataObjectFromWire(w *sharedDataObjectWire) (*SharedDataObject, error return &SharedDataObject{ Name: w.Name, DataObjectType: w.DataObjectType, - AddedAt: w.AddedAt, + AddedAt: addedAtPublicValue, AddedBy: w.AddedBy, Comment: w.Comment, SharedAs: w.SharedAs, CdfEnabled: w.CdfEnabled, HistoryDataSharingStatus: w.HistoryDataSharingStatus, - StartVersion: w.StartVersion, + StartVersion: startVersionPublicValue, Status: w.Status, Content: w.Content, StringSharedAs: w.StringSharedAs, @@ -1384,9 +1534,9 @@ type updateProviderRequestWire struct { Comment *string `json:"comment,omitempty"` Owner *string `json:"owner,omitempty"` RecipientProfile *recipientProfileWire `json:"recipient_profile,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` Cloud *string `json:"cloud,omitempty"` Region *string `json:"region,omitempty"` @@ -1402,6 +1552,14 @@ func updateProviderRequestToWire(v *UpdateProviderRequest) (*updateProviderReque if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateProviderRequest.RecipientProfile", err) } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateProviderRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateProviderRequest.UpdatedAt", err) + } return &updateProviderRequestWire{ NameArg: v.NameArg, NewName: v.NewName, @@ -1411,9 +1569,9 @@ func updateProviderRequestToWire(v *UpdateProviderRequest) (*updateProviderReque Comment: v.Comment, Owner: v.Owner, RecipientProfile: recipientProfileWireValue, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, Cloud: v.Cloud, Region: v.Region, @@ -1433,13 +1591,13 @@ type updateRecipientRequestWire struct { Comment *string `json:"comment,omitempty"` IpAccessList *ipAccessListWire `json:"ip_access_list,omitempty"` PropertiesKvpairs *propertiesKvPairsWire `json:"properties_kvpairs,omitempty"` - ExpirationTime *int64 `json:"expiration_time,omitempty"` + ExpirationTime *wireInt64 `json:"expiration_time,omitempty"` ActivationUrl *string `json:"activation_url,omitempty"` Activated *bool `json:"activated,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` Tokens []recipientTokenInfoWire `json:"tokens,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` Cloud *string `json:"cloud,omitempty"` Region *string `json:"region,omitempty"` @@ -1459,10 +1617,22 @@ func updateRecipientRequestToWire(v *UpdateRecipientRequest) (*updateRecipientRe if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateRecipientRequest.PropertiesKvpairs", err) } + expirationTimeWireValue, err := int64ToWire(v.ExpirationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateRecipientRequest.ExpirationTime", err) + } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateRecipientRequest.CreatedAt", err) + } tokensWireValue, err := convertSlice(v.Tokens, recipientTokenInfoToWire) if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateRecipientRequest.Tokens", err) } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateRecipientRequest.UpdatedAt", err) + } return &updateRecipientRequestWire{ NameArg: v.NameArg, NewName: v.NewName, @@ -1474,13 +1644,13 @@ func updateRecipientRequestToWire(v *UpdateRecipientRequest) (*updateRecipientRe Comment: v.Comment, IpAccessList: ipAccessListWireValue, PropertiesKvpairs: propertiesKvpairsWireValue, - ExpirationTime: v.ExpirationTime, + ExpirationTime: expirationTimeWireValue, ActivationUrl: v.ActivationUrl, Activated: v.Activated, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, Tokens: tokensWireValue, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, Cloud: v.Cloud, Region: v.Region, @@ -1536,9 +1706,9 @@ type updateShareRequestWire struct { Comment *string `json:"comment,omitempty"` StorageRoot *string `json:"storage_root,omitempty"` Objects []sharedDataObjectWire `json:"objects,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` StorageLocation *string `json:"storage_location,omitempty"` } @@ -1555,6 +1725,14 @@ func updateShareRequestToWire(v *UpdateShareRequest) (*updateShareRequestWire, e if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateShareRequest.Objects", err) } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateShareRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateShareRequest.UpdatedAt", err) + } return &updateShareRequestWire{ NameArg: v.NameArg, NewName: v.NewName, @@ -1564,9 +1742,9 @@ func updateShareRequestToWire(v *UpdateShareRequest) (*updateShareRequestWire, e Comment: v.Comment, StorageRoot: v.StorageRoot, Objects: objectsWireValue, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, StorageLocation: v.StorageLocation, }, nil diff --git a/statementexecution/CHANGELOG.md b/statementexecution/CHANGELOG.md index 6224c04..19f237c 100644 --- a/statementexecution/CHANGELOG.md +++ b/statementexecution/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/statementexecution/go.mod b/statementexecution/go.mod index bcd2a35..25a07c3 100644 --- a/statementexecution/go.mod +++ b/statementexecution/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/statementexecution/internal/version.go b/statementexecution/internal/version.go index e5ca1cf..5acfe9d 100644 --- a/statementexecution/internal/version.go +++ b/statementexecution/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-statementexecution" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/statementexecution/v1/client.go b/statementexecution/v1/client.go old mode 100755 new mode 100644 index a1d3b24..215fb90 --- a/statementexecution/v1/client.go +++ b/statementexecution/v1/client.go @@ -76,8 +76,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Requests that an executing statement be canceled. Callers must poll for // status to see the terminal state. Cancel response is empty; receiving // response indicates successful receipt. -func (c *internalClient) CancelStatement(ctx context.Context, req *CancelStatementRequest, opts ...call.Option) (*CancelStatementResponse, error) { - wireReq, err := cancelStatementRequestToWire(req) +func (c *internalClient) CancelStatement(ctx context.Context, req CancelStatementRequest, opts ...call.Option) (*CancelStatementResponse, error) { + wireReq, err := cancelStatementRequestToWire(&req) if err != nil { return nil, err } @@ -98,7 +98,11 @@ func (c *internalClient) CancelStatement(ctx context.Context, req *CancelStateme } pb := pathBuilder{} pb.literal("/api/2.0/sql/statements/") - pb.singleSegment(*req.StatementId) + if req.StatementId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.StatementId) + } pb.literal("/cancel") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -190,8 +194,8 @@ func (c *internalClient) CancelStatement(ctx context.Context, req *CancelStateme // `FAILED` (in contrast to a failure when accepting the request, which results // in a non-200 response). Details of the error can be found at `status.error` // in case of execution failures. -func (c *internalClient) ExecuteStatement(ctx context.Context, req *ExecuteStatementRequest, opts ...call.Option) (*StatementResponse, error) { - wireReq, err := executeStatementRequestToWire(req) +func (c *internalClient) ExecuteStatement(ctx context.Context, req ExecuteStatementRequest, opts ...call.Option) (*StatementResponse, error) { + wireReq, err := executeStatementRequestToWire(&req) if err != nil { return nil, err } @@ -265,7 +269,7 @@ func (c *internalClient) ExecuteStatement(ctx context.Context, req *ExecuteState // fields for simple iteration through the result set. Depending on // `disposition`, the response returns chunks of data either inline, or as // links. -func (c *internalClient) GetResultData(ctx context.Context, req *GetResultDataRequest, opts ...call.Option) (*ResultData, error) { +func (c *internalClient) GetResultData(ctx context.Context, req GetResultDataRequest, opts ...call.Option) (*ResultData, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -279,9 +283,17 @@ func (c *internalClient) GetResultData(ctx context.Context, req *GetResultDataRe } pb := pathBuilder{} pb.literal("/api/2.0/sql/statements/") - pb.singleSegment(*req.StatementId) + if req.StatementId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.StatementId) + } pb.literal("/result/chunks/") - pb.singleSegment(*req.ChunkIndex) + if req.ChunkIndex == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ChunkIndex) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -337,7 +349,7 @@ func (c *internalClient) GetResultData(ctx context.Context, req *GetResultDataRe // // **NOTE** This call currently might take up to 5 seconds to get the latest // status and result. -func (c *internalClient) GetStatementResult(ctx context.Context, req *GetStatementResultRequest, opts ...call.Option) (*StatementResponse, error) { +func (c *internalClient) GetStatementResult(ctx context.Context, req GetStatementResultRequest, opts ...call.Option) (*StatementResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -351,7 +363,11 @@ func (c *internalClient) GetStatementResult(ctx context.Context, req *GetStateme } pb := pathBuilder{} pb.literal("/api/2.0/sql/statements/") - pb.singleSegment(*req.StatementId) + if req.StatementId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.StatementId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/statementexecution/v1/genhelper.go b/statementexecution/v1/genhelper.go old mode 100755 new mode 100644 index ee93097..f5414c3 --- a/statementexecution/v1/genhelper.go +++ b/statementexecution/v1/genhelper.go @@ -144,11 +144,12 @@ func executeCall(ctx context.Context, op func(context.Context) error, opts []cal return ops.Execute(ctx, op, opsOpts...) } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -161,13 +162,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/statementexecution/v1/wire.go b/statementexecution/v1/wire.go old mode 100755 new mode 100644 index 61b43c9..e784b1d --- a/statementexecution/v1/wire.go +++ b/statementexecution/v1/wire.go @@ -3,10 +3,55 @@ package statementexecution import ( + "bytes" "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type cancelStatementRequestWire struct { StatementId *string `json:"statement_id,omitempty"` } @@ -21,23 +66,35 @@ func cancelStatementRequestToWire(v *CancelStatementRequest) (*cancelStatementRe } type chunkInfoWire struct { - ChunkIndex *int `json:"chunk_index,omitempty"` - RowOffset *int64 `json:"row_offset,omitempty"` - RowCount *int64 `json:"row_count,omitempty"` - ByteCount *int64 `json:"byte_count,omitempty"` - NextChunkIndex *int `json:"next_chunk_index,omitempty"` - NextChunkInternalLink *string `json:"next_chunk_internal_link,omitempty"` + ChunkIndex *int `json:"chunk_index,omitempty"` + RowOffset *wireInt64 `json:"row_offset,omitempty"` + RowCount *wireInt64 `json:"row_count,omitempty"` + ByteCount *wireInt64 `json:"byte_count,omitempty"` + NextChunkIndex *int `json:"next_chunk_index,omitempty"` + NextChunkInternalLink *string `json:"next_chunk_internal_link,omitempty"` } func chunkInfoFromWire(w *chunkInfoWire) (*ChunkInfo, error) { if w == nil { return nil, nil } + rowOffsetPublicValue, err := int64FromWire(w.RowOffset) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ChunkInfo.RowOffset", err) + } + rowCountPublicValue, err := int64FromWire(w.RowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ChunkInfo.RowCount", err) + } + byteCountPublicValue, err := int64FromWire(w.ByteCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ChunkInfo.ByteCount", err) + } return &ChunkInfo{ ChunkIndex: w.ChunkIndex, - RowOffset: w.RowOffset, - RowCount: w.RowCount, - ByteCount: w.ByteCount, + RowOffset: rowOffsetPublicValue, + RowCount: rowCountPublicValue, + ByteCount: byteCountPublicValue, NextChunkIndex: w.NextChunkIndex, NextChunkInternalLink: w.NextChunkInternalLink, }, nil @@ -73,8 +130,8 @@ type executeStatementRequestWire struct { WarehouseId *string `json:"warehouse_id,omitempty"` Catalog *string `json:"catalog,omitempty"` Schema *string `json:"schema,omitempty"` - RowLimit *int64 `json:"row_limit,omitempty"` - ByteLimit *int64 `json:"byte_limit,omitempty"` + RowLimit *wireInt64 `json:"row_limit,omitempty"` + ByteLimit *wireInt64 `json:"byte_limit,omitempty"` Format Format `json:"format,omitempty"` Disposition Disposition `json:"disposition,omitempty"` WaitTimeout *string `json:"wait_timeout,omitempty"` @@ -87,6 +144,14 @@ func executeStatementRequestToWire(v *ExecuteStatementRequest) (*executeStatemen if v == nil { return nil, nil } + rowLimitWireValue, err := int64ToWire(v.RowLimit) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ExecuteStatementRequest.RowLimit", err) + } + byteLimitWireValue, err := int64ToWire(v.ByteLimit) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ExecuteStatementRequest.ByteLimit", err) + } parametersWireValue, err := convertSlice(v.Parameters, statementParameterToWire) if err != nil { return nil, fmt.Errorf("%s: %w", "ExecuteStatementRequest.Parameters", err) @@ -100,8 +165,8 @@ func executeStatementRequestToWire(v *ExecuteStatementRequest) (*executeStatemen WarehouseId: v.WarehouseId, Catalog: v.Catalog, Schema: v.Schema, - RowLimit: v.RowLimit, - ByteLimit: v.ByteLimit, + RowLimit: rowLimitWireValue, + ByteLimit: byteLimitWireValue, Format: v.Format, Disposition: v.Disposition, WaitTimeout: v.WaitTimeout, @@ -116,9 +181,9 @@ type externalLinkWire struct { Expiration *string `json:"expiration,omitempty"` HttpHeaders map[string]string `json:"http_headers,omitempty"` ChunkIndex *int `json:"chunk_index,omitempty"` - RowOffset *int64 `json:"row_offset,omitempty"` - RowCount *int64 `json:"row_count,omitempty"` - ByteCount *int64 `json:"byte_count,omitempty"` + RowOffset *wireInt64 `json:"row_offset,omitempty"` + RowCount *wireInt64 `json:"row_count,omitempty"` + ByteCount *wireInt64 `json:"byte_count,omitempty"` NextChunkIndex *int `json:"next_chunk_index,omitempty"` NextChunkInternalLink *string `json:"next_chunk_internal_link,omitempty"` } @@ -127,14 +192,26 @@ func externalLinkFromWire(w *externalLinkWire) (*ExternalLink, error) { if w == nil { return nil, nil } + rowOffsetPublicValue, err := int64FromWire(w.RowOffset) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ExternalLink.RowOffset", err) + } + rowCountPublicValue, err := int64FromWire(w.RowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ExternalLink.RowCount", err) + } + byteCountPublicValue, err := int64FromWire(w.ByteCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ExternalLink.ByteCount", err) + } return &ExternalLink{ ExternalLink: w.ExternalLink, Expiration: w.Expiration, HttpHeaders: w.HttpHeaders, ChunkIndex: w.ChunkIndex, - RowOffset: w.RowOffset, - RowCount: w.RowCount, - ByteCount: w.ByteCount, + RowOffset: rowOffsetPublicValue, + RowCount: rowCountPublicValue, + ByteCount: byteCountPublicValue, NextChunkIndex: w.NextChunkIndex, NextChunkInternalLink: w.NextChunkInternalLink, }, nil @@ -159,9 +236,9 @@ type resultDataWire struct { ExternalLinks []externalLinkWire `json:"external_links,omitempty"` DataArray [][]json.RawMessage `json:"data_array,omitempty"` ChunkIndex *int `json:"chunk_index,omitempty"` - RowOffset *int64 `json:"row_offset,omitempty"` - RowCount *int64 `json:"row_count,omitempty"` - ByteCount *int64 `json:"byte_count,omitempty"` + RowOffset *wireInt64 `json:"row_offset,omitempty"` + RowCount *wireInt64 `json:"row_count,omitempty"` + ByteCount *wireInt64 `json:"byte_count,omitempty"` NextChunkIndex *int `json:"next_chunk_index,omitempty"` NextChunkInternalLink *string `json:"next_chunk_internal_link,omitempty"` } @@ -174,13 +251,25 @@ func resultDataFromWire(w *resultDataWire) (*ResultData, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "ResultData.ExternalLinks", err) } + rowOffsetPublicValue, err := int64FromWire(w.RowOffset) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ResultData.RowOffset", err) + } + rowCountPublicValue, err := int64FromWire(w.RowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ResultData.RowCount", err) + } + byteCountPublicValue, err := int64FromWire(w.ByteCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ResultData.ByteCount", err) + } return &ResultData{ ExternalLinks: externalLinksPublicValue, DataArray: w.DataArray, ChunkIndex: w.ChunkIndex, - RowOffset: w.RowOffset, - RowCount: w.RowCount, - ByteCount: w.ByteCount, + RowOffset: rowOffsetPublicValue, + RowCount: rowCountPublicValue, + ByteCount: byteCountPublicValue, NextChunkIndex: w.NextChunkIndex, NextChunkInternalLink: w.NextChunkInternalLink, }, nil @@ -191,8 +280,8 @@ type resultManifestWire struct { Schema *schemaWire `json:"schema,omitempty"` TotalChunkCount *int `json:"total_chunk_count,omitempty"` Chunks []chunkInfoWire `json:"chunks,omitempty"` - TotalRowCount *int64 `json:"total_row_count,omitempty"` - TotalByteCount *int64 `json:"total_byte_count,omitempty"` + TotalRowCount *wireInt64 `json:"total_row_count,omitempty"` + TotalByteCount *wireInt64 `json:"total_byte_count,omitempty"` Truncated *bool `json:"truncated,omitempty"` } @@ -208,13 +297,21 @@ func resultManifestFromWire(w *resultManifestWire) (*ResultManifest, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "ResultManifest.Chunks", err) } + totalRowCountPublicValue, err := int64FromWire(w.TotalRowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ResultManifest.TotalRowCount", err) + } + totalByteCountPublicValue, err := int64FromWire(w.TotalByteCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ResultManifest.TotalByteCount", err) + } return &ResultManifest{ Format: w.Format, Schema: schemaPublicValue, TotalChunkCount: w.TotalChunkCount, Chunks: chunksPublicValue, - TotalRowCount: w.TotalRowCount, - TotalByteCount: w.TotalByteCount, + TotalRowCount: totalRowCountPublicValue, + TotalByteCount: totalByteCountPublicValue, Truncated: w.Truncated, }, nil } diff --git a/storageconfigurations/CHANGELOG.md b/storageconfigurations/CHANGELOG.md index 6224c04..19f237c 100644 --- a/storageconfigurations/CHANGELOG.md +++ b/storageconfigurations/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/storageconfigurations/go.mod b/storageconfigurations/go.mod index 3b742f1..0a768aa 100644 --- a/storageconfigurations/go.mod +++ b/storageconfigurations/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/storageconfigurations/internal/version.go b/storageconfigurations/internal/version.go index 995b192..969ab69 100644 --- a/storageconfigurations/internal/version.go +++ b/storageconfigurations/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-storageconfigurations" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/storageconfigurations/v1/client.go b/storageconfigurations/v1/client.go old mode 100755 new mode 100644 index d022306..1e99a31 --- a/storageconfigurations/v1/client.go +++ b/storageconfigurations/v1/client.go @@ -76,8 +76,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Creates a storage configuration for an account. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateStorageConfigurationPublic(ctx context.Context, req *CreateStorageConfigurationRequest, opts ...call.Option) (*StorageConfiguration, error) { - wireReq, err := createStorageConfigurationRequestToWire(req) +func (c *internalClient) CreateStorageConfigurationPublic(ctx context.Context, req CreateStorageConfigurationRequest, opts ...call.Option) (*StorageConfiguration, error) { + wireReq, err := createStorageConfigurationRequestToWire(&req) if err != nil { return nil, err } @@ -149,7 +149,7 @@ func (c *internalClient) CreateStorageConfigurationPublic(ctx context.Context, r // Deletes a storage configuration. You cannot delete a storage // configuration that is associated with any workspace. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteStorageConfigurationPublic(ctx context.Context, req *DeleteStorageConfigurationRequest, opts ...call.Option) (*StorageConfiguration, error) { +func (c *internalClient) DeleteStorageConfigurationPublic(ctx context.Context, req DeleteStorageConfigurationRequest, opts ...call.Option) (*StorageConfiguration, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -166,7 +166,11 @@ func (c *internalClient) DeleteStorageConfigurationPublic(ctx context.Context, r pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/storage-configurations/") - pb.singleSegment(*req.StorageConfigurationId) + if req.StorageConfigurationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.StorageConfigurationId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -214,7 +218,7 @@ func (c *internalClient) DeleteStorageConfigurationPublic(ctx context.Context, r // Gets a storage configuration for an account, both specified by // ID. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetStorageConfigurationPublic(ctx context.Context, req *GetStorageConfigurationRequest, opts ...call.Option) (*StorageConfiguration, error) { +func (c *internalClient) GetStorageConfigurationPublic(ctx context.Context, req GetStorageConfigurationRequest, opts ...call.Option) (*StorageConfiguration, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -231,7 +235,11 @@ func (c *internalClient) GetStorageConfigurationPublic(ctx context.Context, req pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/storage-configurations/") - pb.singleSegment(*req.StorageConfigurationId) + if req.StorageConfigurationId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.StorageConfigurationId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -278,7 +286,7 @@ func (c *internalClient) GetStorageConfigurationPublic(ctx context.Context, req // Lists storage configurations for an account, specified by ID. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListStorageConfigurationPublic(ctx context.Context, req *ListStorageConfigurationRequest, opts ...call.Option) (*ListStorageConfigurationResponse, error) { +func (c *internalClient) ListStorageConfigurationPublic(ctx context.Context, req ListStorageConfigurationRequest, opts ...call.Option) (*ListStorageConfigurationResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") diff --git a/storageconfigurations/v1/genhelper.go b/storageconfigurations/v1/genhelper.go old mode 100755 new mode 100644 index d94b43b..e39d482 --- a/storageconfigurations/v1/genhelper.go +++ b/storageconfigurations/v1/genhelper.go @@ -144,11 +144,12 @@ func executeCall(ctx context.Context, op func(context.Context) error, opts []cal return ops.Execute(ctx, op, opsOpts...) } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -161,13 +162,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/storageconfigurations/v1/wire.go b/storageconfigurations/v1/wire.go old mode 100755 new mode 100644 index 2decfa2..0c12dbd --- a/storageconfigurations/v1/wire.go +++ b/storageconfigurations/v1/wire.go @@ -3,9 +3,55 @@ package storageconfigurations import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type createStorageConfigurationRequestWire struct { AccountId *string `json:"account_id,omitempty"` StorageConfigurationName *string `json:"storage_configuration_name,omitempty"` @@ -56,7 +102,7 @@ type storageConfigurationWire struct { AccountId *string `json:"account_id,omitempty"` RootBucketInfo *rootBucketInfoWire `json:"root_bucket_info,omitempty"` StorageConfigurationName *string `json:"storage_configuration_name,omitempty"` - CreationTime *int64 `json:"creation_time,omitempty"` + CreationTime *wireInt64 `json:"creation_time,omitempty"` RoleArn *string `json:"role_arn,omitempty"` } @@ -68,12 +114,16 @@ func storageConfigurationFromWire(w *storageConfigurationWire) (*StorageConfigur if err != nil { return nil, fmt.Errorf("%s: %w", "StorageConfiguration.RootBucketInfo", err) } + creationTimePublicValue, err := int64FromWire(w.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "StorageConfiguration.CreationTime", err) + } return &StorageConfiguration{ StorageConfigurationId: w.StorageConfigurationId, AccountId: w.AccountId, RootBucketInfo: rootBucketInfoPublicValue, StorageConfigurationName: w.StorageConfigurationName, - CreationTime: w.CreationTime, + CreationTime: creationTimePublicValue, RoleArn: w.RoleArn, }, nil } diff --git a/supervisoragents/CHANGELOG.md b/supervisoragents/CHANGELOG.md index 6224c04..19f237c 100644 --- a/supervisoragents/CHANGELOG.md +++ b/supervisoragents/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/supervisoragents/go.mod b/supervisoragents/go.mod index 86243a9..9eae97d 100644 --- a/supervisoragents/go.mod +++ b/supervisoragents/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/supervisoragents/internal/version.go b/supervisoragents/internal/version.go index 15ba9ac..7dbf5af 100644 --- a/supervisoragents/internal/version.go +++ b/supervisoragents/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-supervisoragents" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/supervisoragents/v1/client.go b/supervisoragents/v1/client.go old mode 100755 new mode 100644 index 6263c43..da43f34 --- a/supervisoragents/v1/client.go +++ b/supervisoragents/v1/client.go @@ -75,8 +75,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Creates an example for a Supervisor Agent. -func (c *internalClient) CreateExample(ctx context.Context, req *CreateExampleRequest, opts ...call.Option) (*Example, error) { - wireReq, err := createExampleRequestToWire(req) +func (c *internalClient) CreateExample(ctx context.Context, req CreateExampleRequest, opts ...call.Option) (*Example, error) { + wireReq, err := createExampleRequestToWire(&req) if err != nil { return nil, err } @@ -97,7 +97,11 @@ func (c *internalClient) CreateExample(ctx context.Context, req *CreateExampleRe } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/examples") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -145,8 +149,8 @@ func (c *internalClient) CreateExample(ctx context.Context, req *CreateExampleRe } // Creates a new Supervisor Agent. -func (c *internalClient) CreateSupervisorAgent(ctx context.Context, req *CreateSupervisorAgentRequest, opts ...call.Option) (*SupervisorAgent, error) { - wireReq, err := createSupervisorAgentRequestToWire(req) +func (c *internalClient) CreateSupervisorAgent(ctx context.Context, req CreateSupervisorAgentRequest, opts ...call.Option) (*SupervisorAgent, error) { + wireReq, err := createSupervisorAgentRequestToWire(&req) if err != nil { return nil, err } @@ -218,8 +222,8 @@ func (c *internalClient) CreateSupervisorAgent(ctx context.Context, req *CreateS // accepted and remain equivalent to "dashboard", "table", and // "databricks_web_search" respectively. The "databricks_web_search" tool_type // maps to the `web_search` spec field. -func (c *internalClient) CreateTool(ctx context.Context, req *CreateToolRequest, opts ...call.Option) (*Tool, error) { - wireReq, err := createToolRequestToWire(req) +func (c *internalClient) CreateTool(ctx context.Context, req CreateToolRequest, opts ...call.Option) (*Tool, error) { + wireReq, err := createToolRequestToWire(&req) if err != nil { return nil, err } @@ -240,7 +244,11 @@ func (c *internalClient) CreateTool(ctx context.Context, req *CreateToolRequest, } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/tools") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -291,7 +299,7 @@ func (c *internalClient) CreateTool(ctx context.Context, req *CreateToolRequest, } // Deletes an example from a Supervisor Agent. -func (c *internalClient) DeleteExample(ctx context.Context, req *DeleteExampleRequest, opts ...call.Option) error { +func (c *internalClient) DeleteExample(ctx context.Context, req DeleteExampleRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -305,7 +313,11 @@ func (c *internalClient) DeleteExample(ctx context.Context, req *DeleteExampleRe } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -342,7 +354,7 @@ func (c *internalClient) DeleteExample(ctx context.Context, req *DeleteExampleRe } // Deletes a Supervisor Agent. -func (c *internalClient) DeleteSupervisorAgent(ctx context.Context, req *DeleteSupervisorAgentRequest, opts ...call.Option) error { +func (c *internalClient) DeleteSupervisorAgent(ctx context.Context, req DeleteSupervisorAgentRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -356,7 +368,11 @@ func (c *internalClient) DeleteSupervisorAgent(ctx context.Context, req *DeleteS } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -393,7 +409,7 @@ func (c *internalClient) DeleteSupervisorAgent(ctx context.Context, req *DeleteS } // Deletes a Tool. -func (c *internalClient) DeleteTool(ctx context.Context, req *DeleteToolRequest, opts ...call.Option) error { +func (c *internalClient) DeleteTool(ctx context.Context, req DeleteToolRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -407,7 +423,11 @@ func (c *internalClient) DeleteTool(ctx context.Context, req *DeleteToolRequest, } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -444,7 +464,7 @@ func (c *internalClient) DeleteTool(ctx context.Context, req *DeleteToolRequest, } // Gets an example from a Supervisor Agent. -func (c *internalClient) GetExample(ctx context.Context, req *GetExampleRequest, opts ...call.Option) (*Example, error) { +func (c *internalClient) GetExample(ctx context.Context, req GetExampleRequest, opts ...call.Option) (*Example, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -458,7 +478,11 @@ func (c *internalClient) GetExample(ctx context.Context, req *GetExampleRequest, } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -504,7 +528,7 @@ func (c *internalClient) GetExample(ctx context.Context, req *GetExampleRequest, } // Gets a Supervisor Agent. -func (c *internalClient) GetSupervisorAgent(ctx context.Context, req *GetSupervisorAgentRequest, opts ...call.Option) (*SupervisorAgent, error) { +func (c *internalClient) GetSupervisorAgent(ctx context.Context, req GetSupervisorAgentRequest, opts ...call.Option) (*SupervisorAgent, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -518,7 +542,11 @@ func (c *internalClient) GetSupervisorAgent(ctx context.Context, req *GetSupervi } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -564,7 +592,7 @@ func (c *internalClient) GetSupervisorAgent(ctx context.Context, req *GetSupervi } // Gets a Tool. -func (c *internalClient) GetTool(ctx context.Context, req *GetToolRequest, opts ...call.Option) (*Tool, error) { +func (c *internalClient) GetTool(ctx context.Context, req GetToolRequest, opts ...call.Option) (*Tool, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -578,7 +606,11 @@ func (c *internalClient) GetTool(ctx context.Context, req *GetToolRequest, opts } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -624,8 +656,8 @@ func (c *internalClient) GetTool(ctx context.Context, req *GetToolRequest, opts } // Lists examples under a Supervisor Agent. -func (c *internalClient) ListExamples(ctx context.Context, req *ListExamplesRequest, opts ...call.Option) (*ListExamplesResponse, error) { - wireReq, err := listExamplesRequestToWire(req) +func (c *internalClient) ListExamples(ctx context.Context, req ListExamplesRequest, opts ...call.Option) (*ListExamplesResponse, error) { + wireReq, err := listExamplesRequestToWire(&req) if err != nil { return nil, err } @@ -642,7 +674,11 @@ func (c *internalClient) ListExamples(ctx context.Context, req *ListExamplesRequ } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/examples") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -699,7 +735,7 @@ func (c *internalClient) ListExamples(ctx context.Context, req *ListExamplesRequ // // For example: // -// for item, err := range c.ListExamplesIter(ctx, &ListExamplesRequest{}) { +// for item, err := range c.ListExamplesIter(ctx, ListExamplesRequest{}) { // if err != nil { // return err // } @@ -711,16 +747,13 @@ func (c *internalClient) ListExamples(ctx context.Context, req *ListExamplesRequ // // Callers who need custom pagination logic should use // ListExamples directly. -func (c *internalClient) ListExamplesIter(ctx context.Context, req *ListExamplesRequest, opts ...call.Option) iter.Seq2[*Example, error] { +func (c *internalClient) ListExamplesIter(ctx context.Context, req ListExamplesRequest, opts ...call.Option) iter.Seq2[*Example, error] { return func(yield func(*Example, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListExamplesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListExamples(ctx, &pageReq, opts...) + resp, err := c.ListExamples(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -739,8 +772,8 @@ func (c *internalClient) ListExamplesIter(ctx context.Context, req *ListExamples } // Lists Supervisor Agents. -func (c *internalClient) ListSupervisorAgents(ctx context.Context, req *ListSupervisorAgentsRequest, opts ...call.Option) (*ListSupervisorAgentsResponse, error) { - wireReq, err := listSupervisorAgentsRequestToWire(req) +func (c *internalClient) ListSupervisorAgents(ctx context.Context, req ListSupervisorAgentsRequest, opts ...call.Option) (*ListSupervisorAgentsResponse, error) { + wireReq, err := listSupervisorAgentsRequestToWire(&req) if err != nil { return nil, err } @@ -810,7 +843,7 @@ func (c *internalClient) ListSupervisorAgents(ctx context.Context, req *ListSupe // // For example: // -// for item, err := range c.ListSupervisorAgentsIter(ctx, &ListSupervisorAgentsRequest{}) { +// for item, err := range c.ListSupervisorAgentsIter(ctx, ListSupervisorAgentsRequest{}) { // if err != nil { // return err // } @@ -822,16 +855,13 @@ func (c *internalClient) ListSupervisorAgents(ctx context.Context, req *ListSupe // // Callers who need custom pagination logic should use // ListSupervisorAgents directly. -func (c *internalClient) ListSupervisorAgentsIter(ctx context.Context, req *ListSupervisorAgentsRequest, opts ...call.Option) iter.Seq2[*SupervisorAgent, error] { +func (c *internalClient) ListSupervisorAgentsIter(ctx context.Context, req ListSupervisorAgentsRequest, opts ...call.Option) iter.Seq2[*SupervisorAgent, error] { return func(yield func(*SupervisorAgent, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListSupervisorAgentsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListSupervisorAgents(ctx, &pageReq, opts...) + resp, err := c.ListSupervisorAgents(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -850,8 +880,8 @@ func (c *internalClient) ListSupervisorAgentsIter(ctx context.Context, req *List } // Lists Tools under a Supervisor Agent. -func (c *internalClient) ListTools(ctx context.Context, req *ListToolsRequest, opts ...call.Option) (*ListToolsResponse, error) { - wireReq, err := listToolsRequestToWire(req) +func (c *internalClient) ListTools(ctx context.Context, req ListToolsRequest, opts ...call.Option) (*ListToolsResponse, error) { + wireReq, err := listToolsRequestToWire(&req) if err != nil { return nil, err } @@ -868,7 +898,11 @@ func (c *internalClient) ListTools(ctx context.Context, req *ListToolsRequest, o } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Parent) + if req.Parent == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Parent) + } pb.literal("/tools") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -925,7 +959,7 @@ func (c *internalClient) ListTools(ctx context.Context, req *ListToolsRequest, o // // For example: // -// for item, err := range c.ListToolsIter(ctx, &ListToolsRequest{}) { +// for item, err := range c.ListToolsIter(ctx, ListToolsRequest{}) { // if err != nil { // return err // } @@ -937,16 +971,13 @@ func (c *internalClient) ListTools(ctx context.Context, req *ListToolsRequest, o // // Callers who need custom pagination logic should use // ListTools directly. -func (c *internalClient) ListToolsIter(ctx context.Context, req *ListToolsRequest, opts ...call.Option) iter.Seq2[*Tool, error] { +func (c *internalClient) ListToolsIter(ctx context.Context, req ListToolsRequest, opts ...call.Option) iter.Seq2[*Tool, error] { return func(yield func(*Tool, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListToolsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListTools(ctx, &pageReq, opts...) + resp, err := c.ListTools(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -965,8 +996,8 @@ func (c *internalClient) ListToolsIter(ctx context.Context, req *ListToolsReques } // Updates an example in a Supervisor Agent. -func (c *internalClient) UpdateExample(ctx context.Context, req *UpdateExampleRequest, opts ...call.Option) (*Example, error) { - wireReq, err := updateExampleRequestToWire(req) +func (c *internalClient) UpdateExample(ctx context.Context, req UpdateExampleRequest, opts ...call.Option) (*Example, error) { + wireReq, err := updateExampleRequestToWire(&req) if err != nil { return nil, err } @@ -987,7 +1018,11 @@ func (c *internalClient) UpdateExample(ctx context.Context, req *UpdateExampleRe } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -1038,8 +1073,8 @@ func (c *internalClient) UpdateExample(ctx context.Context, req *UpdateExampleRe // Updates a Supervisor Agent. The fields that are required depend on the paths // specified in `update_mask`. Only fields included in the mask will be updated. -func (c *internalClient) UpdateSupervisorAgent(ctx context.Context, req *UpdateSupervisorAgentRequest, opts ...call.Option) (*SupervisorAgent, error) { - wireReq, err := updateSupervisorAgentRequestToWire(req) +func (c *internalClient) UpdateSupervisorAgent(ctx context.Context, req UpdateSupervisorAgentRequest, opts ...call.Option) (*SupervisorAgent, error) { + wireReq, err := updateSupervisorAgentRequestToWire(&req) if err != nil { return nil, err } @@ -1060,7 +1095,11 @@ func (c *internalClient) UpdateSupervisorAgent(ctx context.Context, req *UpdateS } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.SupervisorAgent.Name) + if req.SupervisorAgent == nil || req.SupervisorAgent.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SupervisorAgent.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -1112,8 +1151,8 @@ func (c *internalClient) UpdateSupervisorAgent(ctx context.Context, req *UpdateS // Updates a Tool. Only the `description` field can be updated. To change // immutable fields such as tool type, spec, or tool ID, delete the tool and // recreate it. -func (c *internalClient) UpdateTool(ctx context.Context, req *UpdateToolRequest, opts ...call.Option) (*Tool, error) { - wireReq, err := updateToolRequestToWire(req) +func (c *internalClient) UpdateTool(ctx context.Context, req UpdateToolRequest, opts ...call.Option) (*Tool, error) { + wireReq, err := updateToolRequestToWire(&req) if err != nil { return nil, err } @@ -1134,7 +1173,11 @@ func (c *internalClient) UpdateTool(ctx context.Context, req *UpdateToolRequest, } pb := pathBuilder{} pb.literal("/api/2.1/") - pb.singleSegment(*req.Tool.Name) + if req.Tool == nil || req.Tool.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Tool.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { diff --git a/supervisoragents/v1/genhelper.go b/supervisoragents/v1/genhelper.go old mode 100755 new mode 100644 index a9b9198..684d50f --- a/supervisoragents/v1/genhelper.go +++ b/supervisoragents/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/tagassignments/CHANGELOG.md b/tagassignments/CHANGELOG.md index 6224c04..19f237c 100644 --- a/tagassignments/CHANGELOG.md +++ b/tagassignments/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/tagassignments/go.mod b/tagassignments/go.mod index 799761f..a48371e 100644 --- a/tagassignments/go.mod +++ b/tagassignments/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/tagassignments/internal/version.go b/tagassignments/internal/version.go index 0127b1f..96fa2fe 100644 --- a/tagassignments/internal/version.go +++ b/tagassignments/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-tagassignments" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/tagassignments/v1/client.go b/tagassignments/v1/client.go old mode 100755 new mode 100644 index 87a6aa8..f2fce00 --- a/tagassignments/v1/client.go +++ b/tagassignments/v1/client.go @@ -75,8 +75,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Create a tag assignment -func (c *internalClient) CreateTagAssignment(ctx context.Context, req *CreateTagAssignmentRequest, opts ...call.Option) (*TagAssignment, error) { - wireReq, err := createTagAssignmentRequestToWire(req) +func (c *internalClient) CreateTagAssignment(ctx context.Context, req CreateTagAssignmentRequest, opts ...call.Option) (*TagAssignment, error) { + wireReq, err := createTagAssignmentRequestToWire(&req) if err != nil { return nil, err } @@ -141,7 +141,7 @@ func (c *internalClient) CreateTagAssignment(ctx context.Context, req *CreateTag } // Delete a tag assignment -func (c *internalClient) DeleteTagAssignment(ctx context.Context, req *DeleteTagAssignmentRequest, opts ...call.Option) error { +func (c *internalClient) DeleteTagAssignment(ctx context.Context, req DeleteTagAssignmentRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -155,11 +155,23 @@ func (c *internalClient) DeleteTagAssignment(ctx context.Context, req *DeleteTag } pb := pathBuilder{} pb.literal("/api/2.0/entity-tag-assignments/") - pb.singleSegment(*req.EntityType) + if req.EntityType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.EntityType) + } pb.literal("/") - pb.singleSegment(*req.EntityId) + if req.EntityId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.EntityId) + } pb.literal("/tags/") - pb.singleSegment(*req.TagKey) + if req.TagKey == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.TagKey) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -196,7 +208,7 @@ func (c *internalClient) DeleteTagAssignment(ctx context.Context, req *DeleteTag } // Get a tag assignment -func (c *internalClient) GetTagAssignment(ctx context.Context, req *GetTagAssignmentRequest, opts ...call.Option) (*TagAssignment, error) { +func (c *internalClient) GetTagAssignment(ctx context.Context, req GetTagAssignmentRequest, opts ...call.Option) (*TagAssignment, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -210,11 +222,23 @@ func (c *internalClient) GetTagAssignment(ctx context.Context, req *GetTagAssign } pb := pathBuilder{} pb.literal("/api/2.0/entity-tag-assignments/") - pb.singleSegment(*req.EntityType) + if req.EntityType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.EntityType) + } pb.literal("/") - pb.singleSegment(*req.EntityId) + if req.EntityId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.EntityId) + } pb.literal("/tags/") - pb.singleSegment(*req.TagKey) + if req.TagKey == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.TagKey) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -260,8 +284,8 @@ func (c *internalClient) GetTagAssignment(ctx context.Context, req *GetTagAssign } // List the tag assignments for an entity -func (c *internalClient) ListTagAssignments(ctx context.Context, req *ListTagAssignmentsRequest, opts ...call.Option) (*ListTagAssignmentsResponse, error) { - wireReq, err := listTagAssignmentsRequestToWire(req) +func (c *internalClient) ListTagAssignments(ctx context.Context, req ListTagAssignmentsRequest, opts ...call.Option) (*ListTagAssignmentsResponse, error) { + wireReq, err := listTagAssignmentsRequestToWire(&req) if err != nil { return nil, err } @@ -278,9 +302,17 @@ func (c *internalClient) ListTagAssignments(ctx context.Context, req *ListTagAss } pb := pathBuilder{} pb.literal("/api/2.0/entity-tag-assignments/") - pb.singleSegment(*req.EntityType) + if req.EntityType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.EntityType) + } pb.literal("/") - pb.singleSegment(*req.EntityId) + if req.EntityId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.EntityId) + } pb.literal("/tags") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -337,7 +369,7 @@ func (c *internalClient) ListTagAssignments(ctx context.Context, req *ListTagAss // // For example: // -// for item, err := range c.ListTagAssignmentsIter(ctx, &ListTagAssignmentsRequest{}) { +// for item, err := range c.ListTagAssignmentsIter(ctx, ListTagAssignmentsRequest{}) { // if err != nil { // return err // } @@ -349,16 +381,13 @@ func (c *internalClient) ListTagAssignments(ctx context.Context, req *ListTagAss // // Callers who need custom pagination logic should use // ListTagAssignments directly. -func (c *internalClient) ListTagAssignmentsIter(ctx context.Context, req *ListTagAssignmentsRequest, opts ...call.Option) iter.Seq2[*TagAssignment, error] { +func (c *internalClient) ListTagAssignmentsIter(ctx context.Context, req ListTagAssignmentsRequest, opts ...call.Option) iter.Seq2[*TagAssignment, error] { return func(yield func(*TagAssignment, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListTagAssignmentsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListTagAssignments(ctx, &pageReq, opts...) + resp, err := c.ListTagAssignments(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -377,8 +406,8 @@ func (c *internalClient) ListTagAssignmentsIter(ctx context.Context, req *ListTa } // Update a tag assignment -func (c *internalClient) UpdateTagAssignment(ctx context.Context, req *UpdateTagAssignmentRequest, opts ...call.Option) (*TagAssignment, error) { - wireReq, err := updateTagAssignmentRequestToWire(req) +func (c *internalClient) UpdateTagAssignment(ctx context.Context, req UpdateTagAssignmentRequest, opts ...call.Option) (*TagAssignment, error) { + wireReq, err := updateTagAssignmentRequestToWire(&req) if err != nil { return nil, err } @@ -399,11 +428,23 @@ func (c *internalClient) UpdateTagAssignment(ctx context.Context, req *UpdateTag } pb := pathBuilder{} pb.literal("/api/2.0/entity-tag-assignments/") - pb.singleSegment(*req.TagAssignment.EntityType) + if req.TagAssignment == nil || req.TagAssignment.EntityType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.TagAssignment.EntityType) + } pb.literal("/") - pb.singleSegment(*req.TagAssignment.EntityId) + if req.TagAssignment == nil || req.TagAssignment.EntityId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.TagAssignment.EntityId) + } pb.literal("/tags/") - pb.singleSegment(*req.TagAssignment.TagKey) + if req.TagAssignment == nil || req.TagAssignment.TagKey == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.TagAssignment.TagKey) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { diff --git a/tagassignments/v1/genhelper.go b/tagassignments/v1/genhelper.go old mode 100755 new mode 100644 index 5bae68c..ee3d411 --- a/tagassignments/v1/genhelper.go +++ b/tagassignments/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/tagpolicies/CHANGELOG.md b/tagpolicies/CHANGELOG.md index 6224c04..19f237c 100644 --- a/tagpolicies/CHANGELOG.md +++ b/tagpolicies/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/tagpolicies/go.mod b/tagpolicies/go.mod index 6b49834..3b7f75d 100644 --- a/tagpolicies/go.mod +++ b/tagpolicies/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/tagpolicies/internal/version.go b/tagpolicies/internal/version.go index 507405b..7492e96 100644 --- a/tagpolicies/internal/version.go +++ b/tagpolicies/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-tagpolicies" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/tagpolicies/v1/client.go b/tagpolicies/v1/client.go old mode 100755 new mode 100644 index 7ca0fca..a6d5808 --- a/tagpolicies/v1/client.go +++ b/tagpolicies/v1/client.go @@ -80,8 +80,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // // [Account Access Control Proxy API]: https://docs.databricks.com/api/workspace/accountaccesscontrolproxy // [Tag Policy Terraform documentation]: https://registry.terraform.io/providers/databricks/databricks/latest/docs/resources/tag_policy -func (c *internalClient) CreateTagPolicy(ctx context.Context, req *CreateTagPolicyRequest, opts ...call.Option) (*TagPolicy, error) { - wireReq, err := createTagPolicyRequestToWire(req) +func (c *internalClient) CreateTagPolicy(ctx context.Context, req CreateTagPolicyRequest, opts ...call.Option) (*TagPolicy, error) { + wireReq, err := createTagPolicyRequestToWire(&req) if err != nil { return nil, err } @@ -150,7 +150,7 @@ func (c *internalClient) CreateTagPolicy(ctx context.Context, req *CreateTagPoli // documentation]. // // [Tag Policy Terraform documentation]: https://registry.terraform.io/providers/databricks/databricks/latest/docs/resources/tag_policy -func (c *internalClient) DeleteTagPolicy(ctx context.Context, req *DeleteTagPolicyRequest, opts ...call.Option) error { +func (c *internalClient) DeleteTagPolicy(ctx context.Context, req DeleteTagPolicyRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -164,7 +164,11 @@ func (c *internalClient) DeleteTagPolicy(ctx context.Context, req *DeleteTagPoli } pb := pathBuilder{} pb.literal("/api/2.1/tag-policies/") - pb.singleSegment(*req.TagKey) + if req.TagKey == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.TagKey) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -206,7 +210,7 @@ func (c *internalClient) DeleteTagPolicy(ctx context.Context, req *DeleteTagPoli // // [Account Access Control Proxy API]: https://docs.databricks.com/api/workspace/accountaccesscontrolproxy // [Tag Policy Terraform documentation]: https://registry.terraform.io/providers/databricks/databricks/latest/docs/data-sources/tag_policy -func (c *internalClient) GetTagPolicy(ctx context.Context, req *GetTagPolicyRequest, opts ...call.Option) (*TagPolicy, error) { +func (c *internalClient) GetTagPolicy(ctx context.Context, req GetTagPolicyRequest, opts ...call.Option) (*TagPolicy, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -220,7 +224,11 @@ func (c *internalClient) GetTagPolicy(ctx context.Context, req *GetTagPolicyRequ } pb := pathBuilder{} pb.literal("/api/2.1/tag-policies/") - pb.singleSegment(*req.TagKey) + if req.TagKey == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.TagKey) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -271,8 +279,8 @@ func (c *internalClient) GetTagPolicy(ctx context.Context, req *GetTagPolicyRequ // // [Account Access Control Proxy API]: https://docs.databricks.com/api/workspace/accountaccesscontrolproxy // [Tag Policy Terraform documentation]: https://registry.terraform.io/providers/databricks/databricks/latest/docs/data-sources/tag_policies -func (c *internalClient) ListTagPolicies(ctx context.Context, req *ListTagPoliciesRequest, opts ...call.Option) (*ListTagPoliciesResponse, error) { - wireReq, err := listTagPoliciesRequestToWire(req) +func (c *internalClient) ListTagPolicies(ctx context.Context, req ListTagPoliciesRequest, opts ...call.Option) (*ListTagPoliciesResponse, error) { + wireReq, err := listTagPoliciesRequestToWire(&req) if err != nil { return nil, err } @@ -342,7 +350,7 @@ func (c *internalClient) ListTagPolicies(ctx context.Context, req *ListTagPolici // // For example: // -// for item, err := range c.ListTagPoliciesIter(ctx, &ListTagPoliciesRequest{}) { +// for item, err := range c.ListTagPoliciesIter(ctx, ListTagPoliciesRequest{}) { // if err != nil { // return err // } @@ -354,16 +362,13 @@ func (c *internalClient) ListTagPolicies(ctx context.Context, req *ListTagPolici // // Callers who need custom pagination logic should use // ListTagPolicies directly. -func (c *internalClient) ListTagPoliciesIter(ctx context.Context, req *ListTagPoliciesRequest, opts ...call.Option) iter.Seq2[*TagPolicy, error] { +func (c *internalClient) ListTagPoliciesIter(ctx context.Context, req ListTagPoliciesRequest, opts ...call.Option) iter.Seq2[*TagPolicy, error] { return func(yield func(*TagPolicy, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListTagPoliciesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListTagPolicies(ctx, &pageReq, opts...) + resp, err := c.ListTagPolicies(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -387,8 +392,8 @@ func (c *internalClient) ListTagPoliciesIter(ctx context.Context, req *ListTagPo // // [Account Access Control Proxy API]: https://docs.databricks.com/api/workspace/accountaccesscontrolproxy // [Tag Policy Terraform documentation]: https://registry.terraform.io/providers/databricks/databricks/latest/docs/resources/tag_policy -func (c *internalClient) UpdateTagPolicy(ctx context.Context, req *UpdateTagPolicyRequest, opts ...call.Option) (*TagPolicy, error) { - wireReq, err := updateTagPolicyRequestToWire(req) +func (c *internalClient) UpdateTagPolicy(ctx context.Context, req UpdateTagPolicyRequest, opts ...call.Option) (*TagPolicy, error) { + wireReq, err := updateTagPolicyRequestToWire(&req) if err != nil { return nil, err } @@ -409,7 +414,11 @@ func (c *internalClient) UpdateTagPolicy(ctx context.Context, req *UpdateTagPoli } pb := pathBuilder{} pb.literal("/api/2.1/tag-policies/") - pb.singleSegment(*req.TagPolicy.TagKey) + if req.TagPolicy == nil || req.TagPolicy.TagKey == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.TagPolicy.TagKey) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { diff --git a/tagpolicies/v1/genhelper.go b/tagpolicies/v1/genhelper.go old mode 100755 new mode 100644 index dda3b9b..79d1925 --- a/tagpolicies/v1/genhelper.go +++ b/tagpolicies/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/tokenmanagement/CHANGELOG.md b/tokenmanagement/CHANGELOG.md index 6224c04..19f237c 100644 --- a/tokenmanagement/CHANGELOG.md +++ b/tokenmanagement/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/tokenmanagement/go.mod b/tokenmanagement/go.mod index b3f18e6..84ae429 100644 --- a/tokenmanagement/go.mod +++ b/tokenmanagement/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/tokenmanagement/internal/version.go b/tokenmanagement/internal/version.go index ed841ed..cc0491f 100644 --- a/tokenmanagement/internal/version.go +++ b/tokenmanagement/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-tokenmanagement" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/tokenmanagement/v1/client.go b/tokenmanagement/v1/client.go old mode 100755 new mode 100644 index c6e2321..12b13b7 --- a/tokenmanagement/v1/client.go +++ b/tokenmanagement/v1/client.go @@ -74,8 +74,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Creates a token on behalf of a service principal. -func (c *internalClient) CreateOnBehalfOfToken(ctx context.Context, req *CreateOnBehalfOfTokenRequest, opts ...call.Option) (*CreateOnBehalfOfTokenResponse, error) { - wireReq, err := createOnBehalfOfTokenRequestToWire(req) +func (c *internalClient) CreateOnBehalfOfToken(ctx context.Context, req CreateOnBehalfOfTokenRequest, opts ...call.Option) (*CreateOnBehalfOfTokenResponse, error) { + wireReq, err := createOnBehalfOfTokenRequestToWire(&req) if err != nil { return nil, err } @@ -140,7 +140,7 @@ func (c *internalClient) CreateOnBehalfOfToken(ctx context.Context, req *CreateO } // Deletes a token, specified by its ID. -func (c *internalClient) DeleteToken(ctx context.Context, req *RevokeTokenRequest, opts ...call.Option) (*RevokeTokenResponse, error) { +func (c *internalClient) DeleteToken(ctx context.Context, req RevokeTokenRequest, opts ...call.Option) (*RevokeTokenResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -154,7 +154,11 @@ func (c *internalClient) DeleteToken(ctx context.Context, req *RevokeTokenReques } pb := pathBuilder{} pb.literal("/api/2.0/token-management/tokens/") - pb.singleSegment(*req.TokenId) + if req.TokenId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.TokenId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -194,7 +198,7 @@ func (c *internalClient) DeleteToken(ctx context.Context, req *RevokeTokenReques } // Gets information about a token, specified by its ID. -func (c *internalClient) GetToken(ctx context.Context, req *GetTokenRequest, opts ...call.Option) (*GetTokenResponse, error) { +func (c *internalClient) GetToken(ctx context.Context, req GetTokenRequest, opts ...call.Option) (*GetTokenResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -208,7 +212,11 @@ func (c *internalClient) GetToken(ctx context.Context, req *GetTokenRequest, opt } pb := pathBuilder{} pb.literal("/api/2.0/token-management/tokens/") - pb.singleSegment(*req.TokenId) + if req.TokenId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.TokenId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -254,8 +262,8 @@ func (c *internalClient) GetToken(ctx context.Context, req *GetTokenRequest, opt } // Lists all tokens associated with the specified workspace or user. -func (c *internalClient) ListTokens(ctx context.Context, req *ListTokensRequest, opts ...call.Option) (*ListTokensResponse, error) { - wireReq, err := listTokensRequestToWire(req) +func (c *internalClient) ListTokens(ctx context.Context, req ListTokensRequest, opts ...call.Option) (*ListTokensResponse, error) { + wireReq, err := listTokensRequestToWire(&req) if err != nil { return nil, err } @@ -321,8 +329,8 @@ func (c *internalClient) ListTokens(ctx context.Context, req *ListTokensRequest, } // Updates a token, specified by its ID. -func (c *internalClient) UpdateToken(ctx context.Context, req *UpdateTokenRequest, opts ...call.Option) (*AdminTokenInfo, error) { - wireReq, err := updateTokenRequestToWire(req) +func (c *internalClient) UpdateToken(ctx context.Context, req UpdateTokenRequest, opts ...call.Option) (*AdminTokenInfo, error) { + wireReq, err := updateTokenRequestToWire(&req) if err != nil { return nil, err } @@ -343,7 +351,11 @@ func (c *internalClient) UpdateToken(ctx context.Context, req *UpdateTokenReques } pb := pathBuilder{} pb.literal("/api/2.0/token-management/tokens/") - pb.singleSegment(*req.Token.TokenId) + if req.Token == nil || req.Token.TokenId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Token.TokenId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/tokenmanagement/v1/genhelper.go b/tokenmanagement/v1/genhelper.go old mode 100755 new mode 100644 index 75abc18..6107ecf --- a/tokenmanagement/v1/genhelper.go +++ b/tokenmanagement/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/tokenmanagement/v1/wire.go b/tokenmanagement/v1/wire.go old mode 100755 new mode 100644 index 280664e..adc729f --- a/tokenmanagement/v1/wire.go +++ b/tokenmanagement/v1/wire.go @@ -3,11 +3,57 @@ package tokenmanagement import ( + "bytes" + "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + func fieldMaskToWire[T any](mask *types.FieldMask[T]) *string { if mask == nil { return nil @@ -18,14 +64,14 @@ func fieldMaskToWire[T any](mask *types.FieldMask[T]) *string { type adminTokenInfoWire struct { TokenId *string `json:"token_id,omitempty"` - CreationTime *int64 `json:"creation_time,omitempty"` - ExpiryTime *int64 `json:"expiry_time,omitempty"` + CreationTime *wireInt64 `json:"creation_time,omitempty"` + ExpiryTime *wireInt64 `json:"expiry_time,omitempty"` Comment *string `json:"comment,omitempty"` - CreatedById *int64 `json:"created_by_id,omitempty"` + CreatedById *wireInt64 `json:"created_by_id,omitempty"` CreatedByUsername *string `json:"created_by_username,omitempty"` - OwnerId *int64 `json:"owner_id,omitempty"` - WorkspaceId *int64 `json:"workspace_id,omitempty"` - LastUsedDay *int64 `json:"last_used_day,omitempty"` + OwnerId *wireInt64 `json:"owner_id,omitempty"` + WorkspaceId *wireInt64 `json:"workspace_id,omitempty"` + LastUsedDay *wireInt64 `json:"last_used_day,omitempty"` Scopes []string `json:"scopes,omitempty"` AutoscopeState AutoscopeState `json:"autoscope_state,omitempty"` InferredScopes []string `json:"inferred_scopes,omitempty"` @@ -36,16 +82,40 @@ func adminTokenInfoToWire(v *AdminTokenInfo) (*adminTokenInfoWire, error) { if v == nil { return nil, nil } + creationTimeWireValue, err := int64ToWire(v.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AdminTokenInfo.CreationTime", err) + } + expiryTimeWireValue, err := int64ToWire(v.ExpiryTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AdminTokenInfo.ExpiryTime", err) + } + createdByIdWireValue, err := int64ToWire(v.CreatedById) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AdminTokenInfo.CreatedById", err) + } + ownerIdWireValue, err := int64ToWire(v.OwnerId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AdminTokenInfo.OwnerId", err) + } + workspaceIdWireValue, err := int64ToWire(v.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AdminTokenInfo.WorkspaceId", err) + } + lastUsedDayWireValue, err := int64ToWire(v.LastUsedDay) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AdminTokenInfo.LastUsedDay", err) + } return &adminTokenInfoWire{ TokenId: v.TokenId, - CreationTime: v.CreationTime, - ExpiryTime: v.ExpiryTime, + CreationTime: creationTimeWireValue, + ExpiryTime: expiryTimeWireValue, Comment: v.Comment, - CreatedById: v.CreatedById, + CreatedById: createdByIdWireValue, CreatedByUsername: v.CreatedByUsername, - OwnerId: v.OwnerId, - WorkspaceId: v.WorkspaceId, - LastUsedDay: v.LastUsedDay, + OwnerId: ownerIdWireValue, + WorkspaceId: workspaceIdWireValue, + LastUsedDay: lastUsedDayWireValue, Scopes: v.Scopes, AutoscopeState: v.AutoscopeState, InferredScopes: v.InferredScopes, @@ -57,16 +127,40 @@ func adminTokenInfoFromWire(w *adminTokenInfoWire) (*AdminTokenInfo, error) { if w == nil { return nil, nil } + creationTimePublicValue, err := int64FromWire(w.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AdminTokenInfo.CreationTime", err) + } + expiryTimePublicValue, err := int64FromWire(w.ExpiryTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AdminTokenInfo.ExpiryTime", err) + } + createdByIdPublicValue, err := int64FromWire(w.CreatedById) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AdminTokenInfo.CreatedById", err) + } + ownerIdPublicValue, err := int64FromWire(w.OwnerId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AdminTokenInfo.OwnerId", err) + } + workspaceIdPublicValue, err := int64FromWire(w.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AdminTokenInfo.WorkspaceId", err) + } + lastUsedDayPublicValue, err := int64FromWire(w.LastUsedDay) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AdminTokenInfo.LastUsedDay", err) + } return &AdminTokenInfo{ TokenId: w.TokenId, - CreationTime: w.CreationTime, - ExpiryTime: w.ExpiryTime, + CreationTime: creationTimePublicValue, + ExpiryTime: expiryTimePublicValue, Comment: w.Comment, - CreatedById: w.CreatedById, + CreatedById: createdByIdPublicValue, CreatedByUsername: w.CreatedByUsername, - OwnerId: w.OwnerId, - WorkspaceId: w.WorkspaceId, - LastUsedDay: w.LastUsedDay, + OwnerId: ownerIdPublicValue, + WorkspaceId: workspaceIdPublicValue, + LastUsedDay: lastUsedDayPublicValue, Scopes: w.Scopes, AutoscopeState: w.AutoscopeState, InferredScopes: w.InferredScopes, @@ -75,20 +169,24 @@ func adminTokenInfoFromWire(w *adminTokenInfoWire) (*AdminTokenInfo, error) { } type createOnBehalfOfTokenRequestWire struct { - ApplicationId *string `json:"application_id,omitempty"` - LifetimeSeconds *int64 `json:"lifetime_seconds,omitempty"` - Comment *string `json:"comment,omitempty"` - Scopes []string `json:"scopes,omitempty"` - AutoscopeEnabled *bool `json:"autoscope_enabled,omitempty"` + ApplicationId *string `json:"application_id,omitempty"` + LifetimeSeconds *wireInt64 `json:"lifetime_seconds,omitempty"` + Comment *string `json:"comment,omitempty"` + Scopes []string `json:"scopes,omitempty"` + AutoscopeEnabled *bool `json:"autoscope_enabled,omitempty"` } func createOnBehalfOfTokenRequestToWire(v *CreateOnBehalfOfTokenRequest) (*createOnBehalfOfTokenRequestWire, error) { if v == nil { return nil, nil } + lifetimeSecondsWireValue, err := int64ToWire(v.LifetimeSeconds) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateOnBehalfOfTokenRequest.LifetimeSeconds", err) + } return &createOnBehalfOfTokenRequestWire{ ApplicationId: v.ApplicationId, - LifetimeSeconds: v.LifetimeSeconds, + LifetimeSeconds: lifetimeSecondsWireValue, Comment: v.Comment, Scopes: v.Scopes, AutoscopeEnabled: v.AutoscopeEnabled, @@ -132,16 +230,20 @@ func getTokenResponseFromWire(w *getTokenResponseWire) (*GetTokenResponse, error } type listTokensRequestWire struct { - CreatedById *int64 `json:"created_by_id,omitempty"` - CreatedByUsername *string `json:"created_by_username,omitempty"` + CreatedById *wireInt64 `json:"created_by_id,omitempty"` + CreatedByUsername *string `json:"created_by_username,omitempty"` } func listTokensRequestToWire(v *ListTokensRequest) (*listTokensRequestWire, error) { if v == nil { return nil, nil } + createdByIdWireValue, err := int64ToWire(v.CreatedById) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListTokensRequest.CreatedById", err) + } return &listTokensRequestWire{ - CreatedById: v.CreatedById, + CreatedById: createdByIdWireValue, CreatedByUsername: v.CreatedByUsername, }, nil } diff --git a/tokens/CHANGELOG.md b/tokens/CHANGELOG.md index 6224c04..19f237c 100644 --- a/tokens/CHANGELOG.md +++ b/tokens/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/tokens/go.mod b/tokens/go.mod index 64dbc98..7200305 100644 --- a/tokens/go.mod +++ b/tokens/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/tokens/internal/version.go b/tokens/internal/version.go index ac6da6d..367b880 100644 --- a/tokens/internal/version.go +++ b/tokens/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-tokens" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/tokens/v1/client.go b/tokens/v1/client.go old mode 100755 new mode 100644 index e262933..52dfe8a --- a/tokens/v1/client.go +++ b/tokens/v1/client.go @@ -77,8 +77,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // authentication, it creates a token with the same client ID as the // authenticated token. If the user's token quota is exceeded, this call returns // an error **QUOTA_EXCEEDED**. -func (c *internalClient) CreateToken(ctx context.Context, req *CreateTokenRequest, opts ...call.Option) (*CreateTokenResponse, error) { - wireReq, err := createTokenRequestToWire(req) +func (c *internalClient) CreateToken(ctx context.Context, req CreateTokenRequest, opts ...call.Option) (*CreateTokenResponse, error) { + wireReq, err := createTokenRequestToWire(&req) if err != nil { return nil, err } @@ -143,7 +143,7 @@ func (c *internalClient) CreateToken(ctx context.Context, req *CreateTokenReques } // Lists all the valid tokens for a user-workspace pair. -func (c *internalClient) ListTokens(ctx context.Context, req *ListTokensRequest, opts ...call.Option) (*ListTokensResponse, error) { +func (c *internalClient) ListTokens(ctx context.Context, req ListTokensRequest, opts ...call.Option) (*ListTokensResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -203,8 +203,8 @@ func (c *internalClient) ListTokens(ctx context.Context, req *ListTokensRequest, // // If a token with the specified ID is not valid, this call returns an error // **RESOURCE_DOES_NOT_EXIST**. -func (c *internalClient) RevokeToken(ctx context.Context, req *RevokeTokenRequest, opts ...call.Option) (*RevokeTokenResponse, error) { - wireReq, err := revokeTokenRequestToWire(req) +func (c *internalClient) RevokeToken(ctx context.Context, req RevokeTokenRequest, opts ...call.Option) (*RevokeTokenResponse, error) { + wireReq, err := revokeTokenRequestToWire(&req) if err != nil { return nil, err } @@ -266,8 +266,8 @@ func (c *internalClient) RevokeToken(ctx context.Context, req *RevokeTokenReques // // If a token with the specified ID is not valid, this call returns an error // **NOT_FOUND**. -func (c *internalClient) UpdateToken(ctx context.Context, req *UpdateTokenRequest, opts ...call.Option) (*UpdateTokenResponse, error) { - wireReq, err := updateTokenRequestToWire(req) +func (c *internalClient) UpdateToken(ctx context.Context, req UpdateTokenRequest, opts ...call.Option) (*UpdateTokenResponse, error) { + wireReq, err := updateTokenRequestToWire(&req) if err != nil { return nil, err } @@ -288,7 +288,11 @@ func (c *internalClient) UpdateToken(ctx context.Context, req *UpdateTokenReques } pb := pathBuilder{} pb.literal("/api/2.0/token/") - pb.singleSegment(*req.TokenId) + if req.TokenId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.TokenId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/tokens/v1/genhelper.go b/tokens/v1/genhelper.go old mode 100755 new mode 100644 index d0d3727..7c640e6 --- a/tokens/v1/genhelper.go +++ b/tokens/v1/genhelper.go @@ -144,11 +144,12 @@ func executeCall(ctx context.Context, op func(context.Context) error, opts []cal return ops.Execute(ctx, op, opsOpts...) } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -161,13 +162,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/tokens/v1/wire.go b/tokens/v1/wire.go old mode 100755 new mode 100644 index f1d57de..d8af392 --- a/tokens/v1/wire.go +++ b/tokens/v1/wire.go @@ -3,11 +3,57 @@ package tokens import ( + "bytes" + "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + func fieldMaskToWire[T any](mask *types.FieldMask[T]) *string { if mask == nil { return nil @@ -17,18 +63,22 @@ func fieldMaskToWire[T any](mask *types.FieldMask[T]) *string { } type createTokenRequestWire struct { - LifetimeSeconds *int64 `json:"lifetime_seconds,omitempty"` - Comment *string `json:"comment,omitempty"` - Scopes []string `json:"scopes,omitempty"` - AutoscopeEnabled *bool `json:"autoscope_enabled,omitempty"` + LifetimeSeconds *wireInt64 `json:"lifetime_seconds,omitempty"` + Comment *string `json:"comment,omitempty"` + Scopes []string `json:"scopes,omitempty"` + AutoscopeEnabled *bool `json:"autoscope_enabled,omitempty"` } func createTokenRequestToWire(v *CreateTokenRequest) (*createTokenRequestWire, error) { if v == nil { return nil, nil } + lifetimeSecondsWireValue, err := int64ToWire(v.LifetimeSeconds) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateTokenRequest.LifetimeSeconds", err) + } return &createTokenRequestWire{ - LifetimeSeconds: v.LifetimeSeconds, + LifetimeSeconds: lifetimeSecondsWireValue, Comment: v.Comment, Scopes: v.Scopes, AutoscopeEnabled: v.AutoscopeEnabled, @@ -73,8 +123,8 @@ func listTokensResponseFromWire(w *listTokensResponseWire) (*ListTokensResponse, type publicTokenInfoWire struct { TokenId *string `json:"token_id,omitempty"` - CreationTime *int64 `json:"creation_time,omitempty"` - ExpiryTime *int64 `json:"expiry_time,omitempty"` + CreationTime *wireInt64 `json:"creation_time,omitempty"` + ExpiryTime *wireInt64 `json:"expiry_time,omitempty"` Comment *string `json:"comment,omitempty"` Scopes []string `json:"scopes,omitempty"` AutoscopeState AutoscopeState `json:"autoscope_state,omitempty"` @@ -86,10 +136,18 @@ func publicTokenInfoToWire(v *PublicTokenInfo) (*publicTokenInfoWire, error) { if v == nil { return nil, nil } + creationTimeWireValue, err := int64ToWire(v.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PublicTokenInfo.CreationTime", err) + } + expiryTimeWireValue, err := int64ToWire(v.ExpiryTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PublicTokenInfo.ExpiryTime", err) + } return &publicTokenInfoWire{ TokenId: v.TokenId, - CreationTime: v.CreationTime, - ExpiryTime: v.ExpiryTime, + CreationTime: creationTimeWireValue, + ExpiryTime: expiryTimeWireValue, Comment: v.Comment, Scopes: v.Scopes, AutoscopeState: v.AutoscopeState, @@ -102,10 +160,18 @@ func publicTokenInfoFromWire(w *publicTokenInfoWire) (*PublicTokenInfo, error) { if w == nil { return nil, nil } + creationTimePublicValue, err := int64FromWire(w.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PublicTokenInfo.CreationTime", err) + } + expiryTimePublicValue, err := int64FromWire(w.ExpiryTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PublicTokenInfo.ExpiryTime", err) + } return &PublicTokenInfo{ TokenId: w.TokenId, - CreationTime: w.CreationTime, - ExpiryTime: w.ExpiryTime, + CreationTime: creationTimePublicValue, + ExpiryTime: expiryTimePublicValue, Comment: w.Comment, Scopes: w.Scopes, AutoscopeState: w.AutoscopeState, diff --git a/uc/abacpolicies/CHANGELOG.md b/uc/abacpolicies/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/abacpolicies/CHANGELOG.md +++ b/uc/abacpolicies/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/abacpolicies/go.mod b/uc/abacpolicies/go.mod index 836252e..5dbd9cd 100644 --- a/uc/abacpolicies/go.mod +++ b/uc/abacpolicies/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/abacpolicies/internal/version.go b/uc/abacpolicies/internal/version.go index cdd62d5..b733d2f 100644 --- a/uc/abacpolicies/internal/version.go +++ b/uc/abacpolicies/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-abacpolicies" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/abacpolicies/v1/client.go b/uc/abacpolicies/v1/client.go old mode 100755 new mode 100644 index 249a235..3e6e247 --- a/uc/abacpolicies/v1/client.go +++ b/uc/abacpolicies/v1/client.go @@ -76,8 +76,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Creates a new policy on a securable. The new policy applies to the securable // and all its descendants. -func (c *internalClient) CreatePolicy(ctx context.Context, req *CreatePolicyRequest, opts ...call.Option) (*PolicyInfo, error) { - wireReq, err := createPolicyRequestToWire(req) +func (c *internalClient) CreatePolicy(ctx context.Context, req CreatePolicyRequest, opts ...call.Option) (*PolicyInfo, error) { + wireReq, err := createPolicyRequestToWire(&req) if err != nil { return nil, err } @@ -142,7 +142,7 @@ func (c *internalClient) CreatePolicy(ctx context.Context, req *CreatePolicyRequ } // Delete an ABAC policy defined on a securable. -func (c *internalClient) DeletePolicy(ctx context.Context, req *DeletePolicyRequest, opts ...call.Option) (*DeletePolicyResponse, error) { +func (c *internalClient) DeletePolicy(ctx context.Context, req DeletePolicyRequest, opts ...call.Option) (*DeletePolicyResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -156,11 +156,23 @@ func (c *internalClient) DeletePolicy(ctx context.Context, req *DeletePolicyRequ } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/policies/") - pb.singleSegment(*req.OnSecurableType) + if req.OnSecurableType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.OnSecurableType) + } pb.literal("/") - pb.singleSegment(*req.OnSecurableFullname) + if req.OnSecurableFullname == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.OnSecurableFullname) + } pb.literal("/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -200,7 +212,7 @@ func (c *internalClient) DeletePolicy(ctx context.Context, req *DeletePolicyRequ } // Get the policy definition on a securable -func (c *internalClient) GetPolicy(ctx context.Context, req *GetPolicyRequest, opts ...call.Option) (*PolicyInfo, error) { +func (c *internalClient) GetPolicy(ctx context.Context, req GetPolicyRequest, opts ...call.Option) (*PolicyInfo, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -214,11 +226,23 @@ func (c *internalClient) GetPolicy(ctx context.Context, req *GetPolicyRequest, o } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/policies/") - pb.singleSegment(*req.OnSecurableType) + if req.OnSecurableType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.OnSecurableType) + } pb.literal("/") - pb.singleSegment(*req.OnSecurableFullname) + if req.OnSecurableFullname == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.OnSecurableFullname) + } pb.literal("/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -270,8 +294,8 @@ func (c *internalClient) GetPolicy(ctx context.Context, req *GetPolicyRequest, o // results while still providing a next_page_token. Clients must continue // reading pages until next_page_token is absent, which is the only indication // that the end of results has been reached. -func (c *internalClient) ListPolicies(ctx context.Context, req *ListPoliciesRequest, opts ...call.Option) (*ListPoliciesResponse, error) { - wireReq, err := listPoliciesRequestToWire(req) +func (c *internalClient) ListPolicies(ctx context.Context, req ListPoliciesRequest, opts ...call.Option) (*ListPoliciesResponse, error) { + wireReq, err := listPoliciesRequestToWire(&req) if err != nil { return nil, err } @@ -288,9 +312,17 @@ func (c *internalClient) ListPolicies(ctx context.Context, req *ListPoliciesRequ } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/policies/") - pb.singleSegment(*req.OnSecurableType) + if req.OnSecurableType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.OnSecurableType) + } pb.literal("/") - pb.singleSegment(*req.OnSecurableFullname) + if req.OnSecurableFullname == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.OnSecurableFullname) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "include_inherited", wireReq.IncludeInherited); err != nil { @@ -349,7 +381,7 @@ func (c *internalClient) ListPolicies(ctx context.Context, req *ListPoliciesRequ // // For example: // -// for item, err := range c.ListPoliciesIter(ctx, &ListPoliciesRequest{}) { +// for item, err := range c.ListPoliciesIter(ctx, ListPoliciesRequest{}) { // if err != nil { // return err // } @@ -361,16 +393,13 @@ func (c *internalClient) ListPolicies(ctx context.Context, req *ListPoliciesRequ // // Callers who need custom pagination logic should use // ListPolicies directly. -func (c *internalClient) ListPoliciesIter(ctx context.Context, req *ListPoliciesRequest, opts ...call.Option) iter.Seq2[*PolicyInfo, error] { +func (c *internalClient) ListPoliciesIter(ctx context.Context, req ListPoliciesRequest, opts ...call.Option) iter.Seq2[*PolicyInfo, error] { return func(yield func(*PolicyInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListPoliciesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListPolicies(ctx, &pageReq, opts...) + resp, err := c.ListPolicies(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -389,8 +418,8 @@ func (c *internalClient) ListPoliciesIter(ctx context.Context, req *ListPolicies } // Update an ABAC policy on a securable. -func (c *internalClient) UpdatePolicy(ctx context.Context, req *UpdatePolicyRequest, opts ...call.Option) (*PolicyInfo, error) { - wireReq, err := updatePolicyRequestToWire(req) +func (c *internalClient) UpdatePolicy(ctx context.Context, req UpdatePolicyRequest, opts ...call.Option) (*PolicyInfo, error) { + wireReq, err := updatePolicyRequestToWire(&req) if err != nil { return nil, err } @@ -411,11 +440,23 @@ func (c *internalClient) UpdatePolicy(ctx context.Context, req *UpdatePolicyRequ } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/policies/") - pb.singleSegment(*req.OnSecurableType) + if req.OnSecurableType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.OnSecurableType) + } pb.literal("/") - pb.singleSegment(*req.OnSecurableFullname) + if req.OnSecurableFullname == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.OnSecurableFullname) + } pb.literal("/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { diff --git a/uc/abacpolicies/v1/genhelper.go b/uc/abacpolicies/v1/genhelper.go old mode 100755 new mode 100644 index 70c1216..eb92a65 --- a/uc/abacpolicies/v1/genhelper.go +++ b/uc/abacpolicies/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/abacpolicies/v1/model.go b/uc/abacpolicies/v1/model.go old mode 100755 new mode 100644 index fc8bcb4..f3d3441 --- a/uc/abacpolicies/v1/model.go +++ b/uc/abacpolicies/v1/model.go @@ -37,7 +37,11 @@ const ( SecurableType_Credential SecurableType = "CREDENTIAL" SecurableType_ExternalMetadata SecurableType = "EXTERNAL_METADATA" // TODO: [UC-2980] Staging tables aren't full-fleged securables yet. - SecurableType_StagingTable SecurableType = "STAGING_TABLE" + SecurableType_StagingTable SecurableType = "STAGING_TABLE" + SecurableType_Model SecurableType = "MODEL" + SecurableType_ModelService SecurableType = "MODEL_SERVICE" + SecurableType_McpService SecurableType = "MCP_SERVICE" + SecurableType_ModelProviderService SecurableType = "MODEL_PROVIDER_SERVICE" ) type ColumnMaskOptions struct { @@ -56,6 +60,15 @@ type ColumnMaskOptions struct { Using []FunctionArgument `fieldmask:"using"` } +// Extracts the value of a column-level tag: get_column_tag_value(col, +// "tagKey").. +type ColumnTagValueExtraction struct { + // The alias from MATCH COLUMNS that identifies the column. + ColumnAlias *string + // 1024 matches the max_length on FunctionArgument.constant above. + TagKey *string +} + type CreatePolicyRequest struct { // Required. The policy to create. PolicyInfo *PolicyInfo @@ -74,6 +87,24 @@ type DeletePolicyRequest struct { type DeletePolicyResponse struct { } +// An expression that is evaluated at query time against per-request context. +// New variants (e.g., identity attributes) are added as additional oneof cases.. +type FunctionArgExpression struct { + Expr isFunctionArgExpression_Expr +} + +type isFunctionArgExpression_Expr interface { + isFunctionArgExpression_Expr() +} + +// FunctionArgExpression_Expr_TagIntrospection selects TagIntrospection for FunctionArgExpression.Expr. +// An expression that introspects tags at query time. +type FunctionArgExpression_Expr_TagIntrospection struct { + TagIntrospection TagIntrospectionExpression +} + +func (*FunctionArgExpression_Expr_TagIntrospection) isFunctionArgExpression_Expr() {} + type FunctionArgument struct { // A positional argument pass to a row filter or column mask function. Arg isFunctionArgument_Arg @@ -99,6 +130,16 @@ type FunctionArgument_Arg_Constant struct { func (*FunctionArgument_Arg_Constant) isFunctionArgument_Arg() {} +// FunctionArgument_Arg_FunctionArgExpression selects FunctionArgExpression for FunctionArgument.Arg. +// An expression evaluated at query time. Wraps per-request expression variants +// (e.g., tag introspection) so new variants can be added without extending the +// FunctionArgument oneof. +type FunctionArgument_Arg_FunctionArgExpression struct { + FunctionArgExpression FunctionArgExpression +} + +func (*FunctionArgument_Arg_FunctionArgExpression) isFunctionArgument_Arg() {} + type GetPolicyRequest struct { // Required. The type of the securable to retrieve the policy for. OnSecurableType *string @@ -247,6 +288,38 @@ type RowFilterOptions struct { Using []FunctionArgument `fieldmask:"using"` } +// An expression that introspects tags at query time.. +type TagIntrospectionExpression struct { + // The tag introspection variant to evaluate at query time. + Expr isTagIntrospectionExpression_Expr +} + +type isTagIntrospectionExpression_Expr interface { + isTagIntrospectionExpression_Expr() +} + +// TagIntrospectionExpression_Expr_TagValue selects TagValue for TagIntrospectionExpression.Expr. +// Extracts the value of a securable-level tag. +type TagIntrospectionExpression_Expr_TagValue struct { + TagValue TagValueExtraction +} + +func (*TagIntrospectionExpression_Expr_TagValue) isTagIntrospectionExpression_Expr() {} + +// TagIntrospectionExpression_Expr_ColumnTagValue selects ColumnTagValue for TagIntrospectionExpression.Expr. +// Extracts the value of a column-level tag. +type TagIntrospectionExpression_Expr_ColumnTagValue struct { + ColumnTagValue ColumnTagValueExtraction +} + +func (*TagIntrospectionExpression_Expr_ColumnTagValue) isTagIntrospectionExpression_Expr() {} + +// Extracts the value of a securable-level tag: get_tag_value("tagKey").. +type TagValueExtraction struct { + // 1024 matches the max_length on FunctionArgument.constant above. + TagKey *string +} + type UpdatePolicyRequest struct { // Required. The type of the securable to update the policy for. OnSecurableType *string diff --git a/uc/abacpolicies/v1/wire.go b/uc/abacpolicies/v1/wire.go old mode 100755 new mode 100644 index c74f3a0..c52cf57 --- a/uc/abacpolicies/v1/wire.go +++ b/uc/abacpolicies/v1/wire.go @@ -3,11 +3,57 @@ package abacpolicies import ( + "bytes" + "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + func fieldMaskToWire[T any](mask *types.FieldMask[T]) *string { if mask == nil { return nil @@ -52,6 +98,31 @@ func columnMaskOptionsFromWire(w *columnMaskOptionsWire) (*ColumnMaskOptions, er }, nil } +type columnTagValueExtractionWire struct { + ColumnAlias *string `json:"column_alias,omitempty"` + TagKey *string `json:"tag_key,omitempty"` +} + +func columnTagValueExtractionToWire(v *ColumnTagValueExtraction) (*columnTagValueExtractionWire, error) { + if v == nil { + return nil, nil + } + return &columnTagValueExtractionWire{ + ColumnAlias: v.ColumnAlias, + TagKey: v.TagKey, + }, nil +} + +func columnTagValueExtractionFromWire(w *columnTagValueExtractionWire) (*ColumnTagValueExtraction, error) { + if w == nil { + return nil, nil + } + return &ColumnTagValueExtraction{ + ColumnAlias: w.ColumnAlias, + TagKey: w.TagKey, + }, nil +} + type createPolicyRequestWire struct { PolicyInfo *policyInfoWire `json:"policy_info,omitempty"` } @@ -69,9 +140,62 @@ func createPolicyRequestToWire(v *CreatePolicyRequest) (*createPolicyRequestWire }, nil } +type functionArgExpressionWire struct { + TagIntrospection *tagIntrospectionExpressionWire `json:"tag_introspection,omitempty"` +} + +func functionArgExpressionToWire(v *FunctionArgExpression) (*functionArgExpressionWire, error) { + if v == nil { + return nil, nil + } + var exprTagIntrospectionWire *tagIntrospectionExpressionWire + switch value := v.Expr.(type) { + case nil: + case *FunctionArgExpression_Expr_TagIntrospection: + if value != nil { + exprTagIntrospectionConverted, err := tagIntrospectionExpressionToWire(&value.TagIntrospection) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FunctionArgExpression.Expr.TagIntrospection", err) + } + exprTagIntrospectionWire = exprTagIntrospectionConverted + } + default: + return nil, fmt.Errorf("%s: unsupported oneof implementation %T", "FunctionArgExpression.Expr", value) + } + return &functionArgExpressionWire{ + TagIntrospection: exprTagIntrospectionWire, + }, nil +} + +func functionArgExpressionFromWire(w *functionArgExpressionWire) (*FunctionArgExpression, error) { + if w == nil { + return nil, nil + } + exprMembers := 0 + if w.TagIntrospection != nil { + exprMembers++ + } + if exprMembers > 1 { + return nil, fmt.Errorf("%s: multiple oneof members set", "FunctionArgExpression.Expr") + } + var exprSelection isFunctionArgExpression_Expr + switch { + case w.TagIntrospection != nil: + exprTagIntrospectionConverted, err := tagIntrospectionExpressionFromWire(w.TagIntrospection) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FunctionArgExpression.Expr.TagIntrospection", err) + } + exprSelection = &FunctionArgExpression_Expr_TagIntrospection{TagIntrospection: *exprTagIntrospectionConverted} + } + return &FunctionArgExpression{ + Expr: exprSelection, + }, nil +} + type functionArgumentWire struct { - Alias *string `json:"alias,omitempty"` - Constant *string `json:"constant,omitempty"` + Alias *string `json:"alias,omitempty"` + Constant *string `json:"constant,omitempty"` + FunctionArgExpression *functionArgExpressionWire `json:"function_arg_expression,omitempty"` } func functionArgumentToWire(v *FunctionArgument) (*functionArgumentWire, error) { @@ -80,6 +204,7 @@ func functionArgumentToWire(v *FunctionArgument) (*functionArgumentWire, error) } var argAliasWire *string var argConstantWire *string + var argFunctionArgExpressionWire *functionArgExpressionWire switch value := v.Arg.(type) { case nil: case *FunctionArgument_Arg_Alias: @@ -90,12 +215,21 @@ func functionArgumentToWire(v *FunctionArgument) (*functionArgumentWire, error) if value != nil { argConstantWire = new(value.Constant) } + case *FunctionArgument_Arg_FunctionArgExpression: + if value != nil { + argFunctionArgExpressionConverted, err := functionArgExpressionToWire(&value.FunctionArgExpression) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FunctionArgument.Arg.FunctionArgExpression", err) + } + argFunctionArgExpressionWire = argFunctionArgExpressionConverted + } default: return nil, fmt.Errorf("%s: unsupported oneof implementation %T", "FunctionArgument.Arg", value) } return &functionArgumentWire{ - Alias: argAliasWire, - Constant: argConstantWire, + Alias: argAliasWire, + Constant: argConstantWire, + FunctionArgExpression: argFunctionArgExpressionWire, }, nil } @@ -110,6 +244,9 @@ func functionArgumentFromWire(w *functionArgumentWire) (*FunctionArgument, error if w.Constant != nil { argMembers++ } + if w.FunctionArgExpression != nil { + argMembers++ + } if argMembers > 1 { return nil, fmt.Errorf("%s: multiple oneof members set", "FunctionArgument.Arg") } @@ -119,6 +256,12 @@ func functionArgumentFromWire(w *functionArgumentWire) (*FunctionArgument, error argSelection = &FunctionArgument_Arg_Alias{Alias: *w.Alias} case w.Constant != nil: argSelection = &FunctionArgument_Arg_Constant{Constant: *w.Constant} + case w.FunctionArgExpression != nil: + argFunctionArgExpressionConverted, err := functionArgExpressionFromWire(w.FunctionArgExpression) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FunctionArgument.Arg.FunctionArgExpression", err) + } + argSelection = &FunctionArgument_Arg_FunctionArgExpression{FunctionArgExpression: *argFunctionArgExpressionConverted} } return &FunctionArgument{ Arg: argSelection, @@ -227,9 +370,9 @@ type policyInfoWire struct { ColumnMask *columnMaskOptionsWire `json:"column_mask,omitempty"` Grant *grantOptionsWire `json:"grant,omitempty"` MatchColumns []matchColumnWire `json:"match_columns,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` } @@ -241,6 +384,14 @@ func policyInfoToWire(v *PolicyInfo) (*policyInfoWire, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "PolicyInfo.MatchColumns", err) } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PolicyInfo.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PolicyInfo.UpdatedAt", err) + } var optionsRowFilterWire *rowFilterOptionsWire var optionsColumnMaskWire *columnMaskOptionsWire var optionsGrantWire *grantOptionsWire @@ -288,9 +439,9 @@ func policyInfoToWire(v *PolicyInfo) (*policyInfoWire, error) { ColumnMask: optionsColumnMaskWire, Grant: optionsGrantWire, MatchColumns: matchColumnsWireValue, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, }, nil } @@ -316,6 +467,14 @@ func policyInfoFromWire(w *policyInfoWire) (*PolicyInfo, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "PolicyInfo.MatchColumns", err) } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PolicyInfo.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PolicyInfo.UpdatedAt", err) + } var optionsSelection isPolicyInfo_Options switch { case w.RowFilter != nil: @@ -349,9 +508,9 @@ func policyInfoFromWire(w *policyInfoWire) (*PolicyInfo, error) { WhenCondition: w.WhenCondition, PolicyType: w.PolicyType, MatchColumns: matchColumnsPublicValue, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, Options: optionsSelection, }, nil @@ -390,6 +549,100 @@ func rowFilterOptionsFromWire(w *rowFilterOptionsWire) (*RowFilterOptions, error }, nil } +type tagIntrospectionExpressionWire struct { + TagValue *tagValueExtractionWire `json:"tag_value,omitempty"` + ColumnTagValue *columnTagValueExtractionWire `json:"column_tag_value,omitempty"` +} + +func tagIntrospectionExpressionToWire(v *TagIntrospectionExpression) (*tagIntrospectionExpressionWire, error) { + if v == nil { + return nil, nil + } + var exprTagValueWire *tagValueExtractionWire + var exprColumnTagValueWire *columnTagValueExtractionWire + switch value := v.Expr.(type) { + case nil: + case *TagIntrospectionExpression_Expr_TagValue: + if value != nil { + exprTagValueConverted, err := tagValueExtractionToWire(&value.TagValue) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TagIntrospectionExpression.Expr.TagValue", err) + } + exprTagValueWire = exprTagValueConverted + } + case *TagIntrospectionExpression_Expr_ColumnTagValue: + if value != nil { + exprColumnTagValueConverted, err := columnTagValueExtractionToWire(&value.ColumnTagValue) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TagIntrospectionExpression.Expr.ColumnTagValue", err) + } + exprColumnTagValueWire = exprColumnTagValueConverted + } + default: + return nil, fmt.Errorf("%s: unsupported oneof implementation %T", "TagIntrospectionExpression.Expr", value) + } + return &tagIntrospectionExpressionWire{ + TagValue: exprTagValueWire, + ColumnTagValue: exprColumnTagValueWire, + }, nil +} + +func tagIntrospectionExpressionFromWire(w *tagIntrospectionExpressionWire) (*TagIntrospectionExpression, error) { + if w == nil { + return nil, nil + } + exprMembers := 0 + if w.TagValue != nil { + exprMembers++ + } + if w.ColumnTagValue != nil { + exprMembers++ + } + if exprMembers > 1 { + return nil, fmt.Errorf("%s: multiple oneof members set", "TagIntrospectionExpression.Expr") + } + var exprSelection isTagIntrospectionExpression_Expr + switch { + case w.TagValue != nil: + exprTagValueConverted, err := tagValueExtractionFromWire(w.TagValue) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TagIntrospectionExpression.Expr.TagValue", err) + } + exprSelection = &TagIntrospectionExpression_Expr_TagValue{TagValue: *exprTagValueConverted} + case w.ColumnTagValue != nil: + exprColumnTagValueConverted, err := columnTagValueExtractionFromWire(w.ColumnTagValue) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TagIntrospectionExpression.Expr.ColumnTagValue", err) + } + exprSelection = &TagIntrospectionExpression_Expr_ColumnTagValue{ColumnTagValue: *exprColumnTagValueConverted} + } + return &TagIntrospectionExpression{ + Expr: exprSelection, + }, nil +} + +type tagValueExtractionWire struct { + TagKey *string `json:"tag_key,omitempty"` +} + +func tagValueExtractionToWire(v *TagValueExtraction) (*tagValueExtractionWire, error) { + if v == nil { + return nil, nil + } + return &tagValueExtractionWire{ + TagKey: v.TagKey, + }, nil +} + +func tagValueExtractionFromWire(w *tagValueExtractionWire) (*TagValueExtraction, error) { + if w == nil { + return nil, nil + } + return &TagValueExtraction{ + TagKey: w.TagKey, + }, nil +} + type updatePolicyRequestWire struct { OnSecurableType *string `json:"on_securable_type,omitempty"` OnSecurableFullname *string `json:"on_securable_fullname,omitempty"` diff --git a/uc/artifactallowlists/CHANGELOG.md b/uc/artifactallowlists/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/artifactallowlists/CHANGELOG.md +++ b/uc/artifactallowlists/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/artifactallowlists/go.mod b/uc/artifactallowlists/go.mod index 6432337..bee5cd4 100644 --- a/uc/artifactallowlists/go.mod +++ b/uc/artifactallowlists/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/artifactallowlists/internal/version.go b/uc/artifactallowlists/internal/version.go index a956af1..aaa75d4 100644 --- a/uc/artifactallowlists/internal/version.go +++ b/uc/artifactallowlists/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-artifactallowlists" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/artifactallowlists/v1/client.go b/uc/artifactallowlists/v1/client.go old mode 100755 new mode 100644 index e4f2357..9a0d98b --- a/uc/artifactallowlists/v1/client.go +++ b/uc/artifactallowlists/v1/client.go @@ -6,7 +6,6 @@ import ( "bytes" "context" "encoding/json" - "fmt" "log/slog" "net/http" "net/url" @@ -76,7 +75,7 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Get the artifact allowlist of a certain artifact type. The caller must be a // metastore admin or have the **MANAGE ALLOWLIST** privilege on the metastore. -func (c *internalClient) GetArtifactAllowlist(ctx context.Context, req *GetArtifactAllowlistRequest, opts ...call.Option) (*ArtifactAllowlistInfo, error) { +func (c *internalClient) GetArtifactAllowlist(ctx context.Context, req GetArtifactAllowlistRequest, opts ...call.Option) (*ArtifactAllowlistInfo, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -88,9 +87,6 @@ func (c *internalClient) GetArtifactAllowlist(ctx context.Context, req *GetArtif if err != nil { return nil, err } - if req.ArtifactType == "" { - return nil, fmt.Errorf("path parameter %q is required", "artifact_type") - } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/artifact-allowlists/") pb.singleSegment(req.ArtifactType) @@ -141,8 +137,8 @@ func (c *internalClient) GetArtifactAllowlist(ctx context.Context, req *GetArtif // Set the artifact allowlist of a certain artifact type. The whole artifact // allowlist is replaced with the new allowlist. The caller must be a metastore // admin or have the **MANAGE ALLOWLIST** privilege on the metastore. -func (c *internalClient) SetArtifactAllowlist(ctx context.Context, req *SetArtifactAllowlistRequest, opts ...call.Option) (*ArtifactAllowlistInfo, error) { - wireReq, err := setArtifactAllowlistRequestToWire(req) +func (c *internalClient) SetArtifactAllowlist(ctx context.Context, req SetArtifactAllowlistRequest, opts ...call.Option) (*ArtifactAllowlistInfo, error) { + wireReq, err := setArtifactAllowlistRequestToWire(&req) if err != nil { return nil, err } @@ -161,9 +157,6 @@ func (c *internalClient) SetArtifactAllowlist(ctx context.Context, req *SetArtif if err != nil { return nil, err } - if req.ArtifactType == "" { - return nil, fmt.Errorf("path parameter %q is required", "artifact_type") - } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/artifact-allowlists/") pb.singleSegment(req.ArtifactType) diff --git a/uc/artifactallowlists/v1/genhelper.go b/uc/artifactallowlists/v1/genhelper.go old mode 100755 new mode 100644 index cc99424..2105a9c --- a/uc/artifactallowlists/v1/genhelper.go +++ b/uc/artifactallowlists/v1/genhelper.go @@ -144,11 +144,12 @@ func executeCall(ctx context.Context, op func(context.Context) error, opts []cal return ops.Execute(ctx, op, opsOpts...) } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -161,13 +162,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/artifactallowlists/v1/wire.go b/uc/artifactallowlists/v1/wire.go old mode 100755 new mode 100644 index ba4232b..438c7da --- a/uc/artifactallowlists/v1/wire.go +++ b/uc/artifactallowlists/v1/wire.go @@ -3,14 +3,60 @@ package artifactallowlists import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type artifactAllowlistInfoWire struct { ArtifactMatchers []artifactMatcherWire `json:"artifact_matchers,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` } func artifactAllowlistInfoFromWire(w *artifactAllowlistInfoWire) (*ArtifactAllowlistInfo, error) { @@ -21,11 +67,15 @@ func artifactAllowlistInfoFromWire(w *artifactAllowlistInfoWire) (*ArtifactAllow if err != nil { return nil, fmt.Errorf("%s: %w", "ArtifactAllowlistInfo.ArtifactMatchers", err) } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ArtifactAllowlistInfo.CreatedAt", err) + } return &ArtifactAllowlistInfo{ ArtifactMatchers: artifactMatchersPublicValue, MetastoreId: w.MetastoreId, CreatedBy: w.CreatedBy, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, }, nil } @@ -59,7 +109,7 @@ type setArtifactAllowlistRequestWire struct { ArtifactMatchers []artifactMatcherWire `json:"artifact_matchers,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` } func setArtifactAllowlistRequestToWire(v *SetArtifactAllowlistRequest) (*setArtifactAllowlistRequestWire, error) { @@ -70,12 +120,16 @@ func setArtifactAllowlistRequestToWire(v *SetArtifactAllowlistRequest) (*setArti if err != nil { return nil, fmt.Errorf("%s: %w", "SetArtifactAllowlistRequest.ArtifactMatchers", err) } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SetArtifactAllowlistRequest.CreatedAt", err) + } return &setArtifactAllowlistRequestWire{ ArtifactType: v.ArtifactType, ArtifactMatchers: artifactMatchersWireValue, MetastoreId: v.MetastoreId, CreatedBy: v.CreatedBy, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, }, nil } diff --git a/uc/catalogs/CHANGELOG.md b/uc/catalogs/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/catalogs/CHANGELOG.md +++ b/uc/catalogs/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/catalogs/go.mod b/uc/catalogs/go.mod index 42b45eb..56ce076 100644 --- a/uc/catalogs/go.mod +++ b/uc/catalogs/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/catalogs/internal/version.go b/uc/catalogs/internal/version.go index b21693a..c9003de 100644 --- a/uc/catalogs/internal/version.go +++ b/uc/catalogs/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-catalogs" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/catalogs/v1/client.go b/uc/catalogs/v1/client.go old mode 100755 new mode 100644 index 9bbb1dc..ac35f9f --- a/uc/catalogs/v1/client.go +++ b/uc/catalogs/v1/client.go @@ -76,8 +76,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Creates a new catalog instance in the parent metastore if the caller is a // metastore admin or has the **CREATE_CATALOG** privilege. -func (c *internalClient) CreateCatalog(ctx context.Context, req *CreateCatalogRequest, opts ...call.Option) (*CatalogInfo, error) { - wireReq, err := createCatalogRequestToWire(req) +func (c *internalClient) CreateCatalog(ctx context.Context, req CreateCatalogRequest, opts ...call.Option) (*CatalogInfo, error) { + wireReq, err := createCatalogRequestToWire(&req) if err != nil { return nil, err } @@ -143,8 +143,8 @@ func (c *internalClient) CreateCatalog(ctx context.Context, req *CreateCatalogRe // Deletes the catalog that matches the supplied name. The caller must be a // metastore admin or the owner of the catalog. -func (c *internalClient) DeleteCatalog(ctx context.Context, req *DeleteCatalogRequest, opts ...call.Option) (*DeleteCatalogResponse, error) { - wireReq, err := deleteCatalogRequestToWire(req) +func (c *internalClient) DeleteCatalog(ctx context.Context, req DeleteCatalogRequest, opts ...call.Option) (*DeleteCatalogResponse, error) { + wireReq, err := deleteCatalogRequestToWire(&req) if err != nil { return nil, err } @@ -161,7 +161,11 @@ func (c *internalClient) DeleteCatalog(ctx context.Context, req *DeleteCatalogRe } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/catalogs/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "force", wireReq.Force); err != nil { @@ -206,8 +210,8 @@ func (c *internalClient) DeleteCatalog(ctx context.Context, req *DeleteCatalogRe // Gets the specified catalog in a metastore. The caller must be a metastore // admin, the owner of the catalog, or a user that has the **USE_CATALOG** // privilege set for their account. -func (c *internalClient) GetCatalog(ctx context.Context, req *GetCatalogRequest, opts ...call.Option) (*CatalogInfo, error) { - wireReq, err := getCatalogRequestToWire(req) +func (c *internalClient) GetCatalog(ctx context.Context, req GetCatalogRequest, opts ...call.Option) (*CatalogInfo, error) { + wireReq, err := getCatalogRequestToWire(&req) if err != nil { return nil, err } @@ -224,7 +228,11 @@ func (c *internalClient) GetCatalog(ctx context.Context, req *GetCatalogRequest, } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/catalogs/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "include_browse", wireReq.IncludeBrowse); err != nil { @@ -285,8 +293,8 @@ func (c *internalClient) GetCatalog(ctx context.Context, req *GetCatalogRequest, // contain zero results while still providing a next_page_token. Clients must // continue reading pages until next_page_token is absent, which is the only // indication that the end of results has been reached. -func (c *internalClient) ListCatalogs(ctx context.Context, req *ListCatalogsRequest, opts ...call.Option) (*ListCatalogsResponse, error) { - wireReq, err := listCatalogsRequestToWire(req) +func (c *internalClient) ListCatalogs(ctx context.Context, req ListCatalogsRequest, opts ...call.Option) (*ListCatalogsResponse, error) { + wireReq, err := listCatalogsRequestToWire(&req) if err != nil { return nil, err } @@ -362,7 +370,7 @@ func (c *internalClient) ListCatalogs(ctx context.Context, req *ListCatalogsRequ // // For example: // -// for item, err := range c.ListCatalogsIter(ctx, &ListCatalogsRequest{}) { +// for item, err := range c.ListCatalogsIter(ctx, ListCatalogsRequest{}) { // if err != nil { // return err // } @@ -374,16 +382,13 @@ func (c *internalClient) ListCatalogs(ctx context.Context, req *ListCatalogsRequ // // Callers who need custom pagination logic should use // ListCatalogs directly. -func (c *internalClient) ListCatalogsIter(ctx context.Context, req *ListCatalogsRequest, opts ...call.Option) iter.Seq2[*CatalogInfo, error] { +func (c *internalClient) ListCatalogsIter(ctx context.Context, req ListCatalogsRequest, opts ...call.Option) iter.Seq2[*CatalogInfo, error] { return func(yield func(*CatalogInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListCatalogsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListCatalogs(ctx, &pageReq, opts...) + resp, err := c.ListCatalogs(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -404,8 +409,8 @@ func (c *internalClient) ListCatalogsIter(ctx context.Context, req *ListCatalogs // Updates the catalog that matches the supplied name. The caller must be either // the owner of the catalog, or a metastore admin (when changing the owner field // of the catalog). -func (c *internalClient) UpdateCatalog(ctx context.Context, req *UpdateCatalogRequest, opts ...call.Option) (*CatalogInfo, error) { - wireReq, err := updateCatalogRequestToWire(req) +func (c *internalClient) UpdateCatalog(ctx context.Context, req UpdateCatalogRequest, opts ...call.Option) (*CatalogInfo, error) { + wireReq, err := updateCatalogRequestToWire(&req) if err != nil { return nil, err } @@ -426,7 +431,11 @@ func (c *internalClient) UpdateCatalog(ctx context.Context, req *UpdateCatalogRe } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/catalogs/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/uc/catalogs/v1/genhelper.go b/uc/catalogs/v1/genhelper.go old mode 100755 new mode 100644 index 86023d5..9a760dd --- a/uc/catalogs/v1/genhelper.go +++ b/uc/catalogs/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/catalogs/v1/model.go b/uc/catalogs/v1/model.go old mode 100755 new mode 100644 index 45bd8d0..8cd2831 --- a/uc/catalogs/v1/model.go +++ b/uc/catalogs/v1/model.go @@ -45,7 +45,11 @@ const ( SecurableType_Credential SecurableType = "CREDENTIAL" SecurableType_ExternalMetadata SecurableType = "EXTERNAL_METADATA" // TODO: [UC-2980] Staging tables aren't full-fleged securables yet. - SecurableType_StagingTable SecurableType = "STAGING_TABLE" + SecurableType_StagingTable SecurableType = "STAGING_TABLE" + SecurableType_Model SecurableType = "MODEL" + SecurableType_ModelService SecurableType = "MODEL_SERVICE" + SecurableType_McpService SecurableType = "MCP_SERVICE" + SecurableType_ModelProviderService SecurableType = "MODEL_PROVIDER_SERVICE" ) type ProvisioningInfo_State string diff --git a/uc/catalogs/v1/wire.go b/uc/catalogs/v1/wire.go old mode 100755 new mode 100644 index 1619bed..45a4265 --- a/uc/catalogs/v1/wire.go +++ b/uc/catalogs/v1/wire.go @@ -3,9 +3,55 @@ package catalogs import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type azureEncryptionSettingsWire struct { AzureTenantId *string `json:"azure_tenant_id,omitempty"` AzureCmkAccessConnectorId *string `json:"azure_cmk_access_connector_id,omitempty"` @@ -45,9 +91,9 @@ type catalogInfoWire struct { ShareName *string `json:"share_name,omitempty"` ConnectionName *string `json:"connection_name,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` StorageLocation *string `json:"storage_location,omitempty"` IsolationMode CatalogIsolationMode `json:"isolation_mode,omitempty"` @@ -56,7 +102,7 @@ type catalogInfoWire struct { ProvisioningInfo *provisioningInfoWire `json:"provisioning_info,omitempty"` FullName *string `json:"full_name,omitempty"` SecurableType SecurableType `json:"securable_type,omitempty"` - CustomMaxRetentionHours *int64 `json:"custom_max_retention_hours,omitempty"` + CustomMaxRetentionHours *wireInt64 `json:"custom_max_retention_hours,omitempty"` ManagedEncryptionSettings *encryptionSettingsWire `json:"managed_encryption_settings,omitempty"` Properties map[string]string `json:"properties,omitempty"` Options map[string]string `json:"options,omitempty"` @@ -66,6 +112,14 @@ func catalogInfoFromWire(w *catalogInfoWire) (*CatalogInfo, error) { if w == nil { return nil, nil } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CatalogInfo.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CatalogInfo.UpdatedAt", err) + } effectivePredictiveOptimizationFlagPublicValue, err := effectivePredictiveOptimizationFlagFromWire(w.EffectivePredictiveOptimizationFlag) if err != nil { return nil, fmt.Errorf("%s: %w", "CatalogInfo.EffectivePredictiveOptimizationFlag", err) @@ -74,6 +128,10 @@ func catalogInfoFromWire(w *catalogInfoWire) (*CatalogInfo, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "CatalogInfo.ProvisioningInfo", err) } + customMaxRetentionHoursPublicValue, err := int64FromWire(w.CustomMaxRetentionHours) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CatalogInfo.CustomMaxRetentionHours", err) + } managedEncryptionSettingsPublicValue, err := encryptionSettingsFromWire(w.ManagedEncryptionSettings) if err != nil { return nil, fmt.Errorf("%s: %w", "CatalogInfo.ManagedEncryptionSettings", err) @@ -89,9 +147,9 @@ func catalogInfoFromWire(w *catalogInfoWire) (*CatalogInfo, error) { ShareName: w.ShareName, ConnectionName: w.ConnectionName, MetastoreId: w.MetastoreId, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, StorageLocation: w.StorageLocation, IsolationMode: w.IsolationMode, @@ -100,7 +158,7 @@ func catalogInfoFromWire(w *catalogInfoWire) (*CatalogInfo, error) { ProvisioningInfo: provisioningInfoPublicValue, FullName: w.FullName, SecurableType: w.SecurableType, - CustomMaxRetentionHours: w.CustomMaxRetentionHours, + CustomMaxRetentionHours: customMaxRetentionHoursPublicValue, ManagedEncryptionSettings: managedEncryptionSettingsPublicValue, Properties: w.Properties, Options: w.Options, @@ -118,9 +176,9 @@ type createCatalogRequestWire struct { ShareName *string `json:"share_name,omitempty"` ConnectionName *string `json:"connection_name,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` StorageLocation *string `json:"storage_location,omitempty"` IsolationMode CatalogIsolationMode `json:"isolation_mode,omitempty"` @@ -129,7 +187,7 @@ type createCatalogRequestWire struct { ProvisioningInfo *provisioningInfoWire `json:"provisioning_info,omitempty"` FullName *string `json:"full_name,omitempty"` SecurableType SecurableType `json:"securable_type,omitempty"` - CustomMaxRetentionHours *int64 `json:"custom_max_retention_hours,omitempty"` + CustomMaxRetentionHours *wireInt64 `json:"custom_max_retention_hours,omitempty"` ManagedEncryptionSettings *encryptionSettingsWire `json:"managed_encryption_settings,omitempty"` Properties map[string]string `json:"properties,omitempty"` Options map[string]string `json:"options,omitempty"` @@ -139,6 +197,14 @@ func createCatalogRequestToWire(v *CreateCatalogRequest) (*createCatalogRequestW if v == nil { return nil, nil } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateCatalogRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateCatalogRequest.UpdatedAt", err) + } effectivePredictiveOptimizationFlagWireValue, err := effectivePredictiveOptimizationFlagToWire(v.EffectivePredictiveOptimizationFlag) if err != nil { return nil, fmt.Errorf("%s: %w", "CreateCatalogRequest.EffectivePredictiveOptimizationFlag", err) @@ -147,6 +213,10 @@ func createCatalogRequestToWire(v *CreateCatalogRequest) (*createCatalogRequestW if err != nil { return nil, fmt.Errorf("%s: %w", "CreateCatalogRequest.ProvisioningInfo", err) } + customMaxRetentionHoursWireValue, err := int64ToWire(v.CustomMaxRetentionHours) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateCatalogRequest.CustomMaxRetentionHours", err) + } managedEncryptionSettingsWireValue, err := encryptionSettingsToWire(v.ManagedEncryptionSettings) if err != nil { return nil, fmt.Errorf("%s: %w", "CreateCatalogRequest.ManagedEncryptionSettings", err) @@ -162,9 +232,9 @@ func createCatalogRequestToWire(v *CreateCatalogRequest) (*createCatalogRequestW ShareName: v.ShareName, ConnectionName: v.ConnectionName, MetastoreId: v.MetastoreId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, StorageLocation: v.StorageLocation, IsolationMode: v.IsolationMode, @@ -173,7 +243,7 @@ func createCatalogRequestToWire(v *CreateCatalogRequest) (*createCatalogRequestW ProvisioningInfo: provisioningInfoWireValue, FullName: v.FullName, SecurableType: v.SecurableType, - CustomMaxRetentionHours: v.CustomMaxRetentionHours, + CustomMaxRetentionHours: customMaxRetentionHoursWireValue, ManagedEncryptionSettings: managedEncryptionSettingsWireValue, Properties: v.Properties, Options: v.Options, @@ -347,9 +417,9 @@ type updateCatalogRequestWire struct { ShareName *string `json:"share_name,omitempty"` ConnectionName *string `json:"connection_name,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` StorageLocation *string `json:"storage_location,omitempty"` IsolationMode CatalogIsolationMode `json:"isolation_mode,omitempty"` @@ -358,7 +428,7 @@ type updateCatalogRequestWire struct { ProvisioningInfo *provisioningInfoWire `json:"provisioning_info,omitempty"` FullName *string `json:"full_name,omitempty"` SecurableType SecurableType `json:"securable_type,omitempty"` - CustomMaxRetentionHours *int64 `json:"custom_max_retention_hours,omitempty"` + CustomMaxRetentionHours *wireInt64 `json:"custom_max_retention_hours,omitempty"` ManagedEncryptionSettings *encryptionSettingsWire `json:"managed_encryption_settings,omitempty"` Properties map[string]string `json:"properties,omitempty"` Options map[string]string `json:"options,omitempty"` @@ -368,6 +438,14 @@ func updateCatalogRequestToWire(v *UpdateCatalogRequest) (*updateCatalogRequestW if v == nil { return nil, nil } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateCatalogRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateCatalogRequest.UpdatedAt", err) + } effectivePredictiveOptimizationFlagWireValue, err := effectivePredictiveOptimizationFlagToWire(v.EffectivePredictiveOptimizationFlag) if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateCatalogRequest.EffectivePredictiveOptimizationFlag", err) @@ -376,6 +454,10 @@ func updateCatalogRequestToWire(v *UpdateCatalogRequest) (*updateCatalogRequestW if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateCatalogRequest.ProvisioningInfo", err) } + customMaxRetentionHoursWireValue, err := int64ToWire(v.CustomMaxRetentionHours) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateCatalogRequest.CustomMaxRetentionHours", err) + } managedEncryptionSettingsWireValue, err := encryptionSettingsToWire(v.ManagedEncryptionSettings) if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateCatalogRequest.ManagedEncryptionSettings", err) @@ -393,9 +475,9 @@ func updateCatalogRequestToWire(v *UpdateCatalogRequest) (*updateCatalogRequestW ShareName: v.ShareName, ConnectionName: v.ConnectionName, MetastoreId: v.MetastoreId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, StorageLocation: v.StorageLocation, IsolationMode: v.IsolationMode, @@ -404,7 +486,7 @@ func updateCatalogRequestToWire(v *UpdateCatalogRequest) (*updateCatalogRequestW ProvisioningInfo: provisioningInfoWireValue, FullName: v.FullName, SecurableType: v.SecurableType, - CustomMaxRetentionHours: v.CustomMaxRetentionHours, + CustomMaxRetentionHours: customMaxRetentionHoursWireValue, ManagedEncryptionSettings: managedEncryptionSettingsWireValue, Properties: v.Properties, Options: v.Options, diff --git a/uc/connections/CHANGELOG.md b/uc/connections/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/connections/CHANGELOG.md +++ b/uc/connections/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/connections/go.mod b/uc/connections/go.mod index 4ccb489..b3ef66c 100644 --- a/uc/connections/go.mod +++ b/uc/connections/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/connections/internal/version.go b/uc/connections/internal/version.go index 69a3a38..349e974 100644 --- a/uc/connections/internal/version.go +++ b/uc/connections/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-connections" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/connections/v1/client.go b/uc/connections/v1/client.go old mode 100755 new mode 100644 index 6476a51..b8a4ebb --- a/uc/connections/v1/client.go +++ b/uc/connections/v1/client.go @@ -79,8 +79,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Creates a new connection to an external data source. It allows users to // specify connection details and configurations for interaction with the // external server. -func (c *internalClient) CreateConnection(ctx context.Context, req *CreateConnectionRequest, opts ...call.Option) (*ConnectionInfo, error) { - wireReq, err := createConnectionRequestToWire(req) +func (c *internalClient) CreateConnection(ctx context.Context, req CreateConnectionRequest, opts ...call.Option) (*ConnectionInfo, error) { + wireReq, err := createConnectionRequestToWire(&req) if err != nil { return nil, err } @@ -145,7 +145,7 @@ func (c *internalClient) CreateConnection(ctx context.Context, req *CreateConnec } // Deletes the connection that matches the supplied name. -func (c *internalClient) DeleteConnection(ctx context.Context, req *DeleteConnectionRequest, opts ...call.Option) (*DeleteConnectionResponse, error) { +func (c *internalClient) DeleteConnection(ctx context.Context, req DeleteConnectionRequest, opts ...call.Option) (*DeleteConnectionResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -159,7 +159,11 @@ func (c *internalClient) DeleteConnection(ctx context.Context, req *DeleteConnec } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/connections/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -199,7 +203,7 @@ func (c *internalClient) DeleteConnection(ctx context.Context, req *DeleteConnec } // Gets a connection from it's name. -func (c *internalClient) GetConnection(ctx context.Context, req *GetConnectionRequest, opts ...call.Option) (*ConnectionInfo, error) { +func (c *internalClient) GetConnection(ctx context.Context, req GetConnectionRequest, opts ...call.Option) (*ConnectionInfo, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -213,7 +217,11 @@ func (c *internalClient) GetConnection(ctx context.Context, req *GetConnectionRe } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/connections/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -267,8 +275,8 @@ func (c *internalClient) GetConnection(ctx context.Context, req *GetConnectionRe // contain zero results while still providing a next_page_token. Clients must // continue reading pages until next_page_token is absent, which is the only // indication that the end of results has been reached. -func (c *internalClient) ListConnections(ctx context.Context, req *ListConnectionsRequest, opts ...call.Option) (*ListConnectionsResponse, error) { - wireReq, err := listConnectionsRequestToWire(req) +func (c *internalClient) ListConnections(ctx context.Context, req ListConnectionsRequest, opts ...call.Option) (*ListConnectionsResponse, error) { + wireReq, err := listConnectionsRequestToWire(&req) if err != nil { return nil, err } @@ -341,7 +349,7 @@ func (c *internalClient) ListConnections(ctx context.Context, req *ListConnectio // // For example: // -// for item, err := range c.ListConnectionsIter(ctx, &ListConnectionsRequest{}) { +// for item, err := range c.ListConnectionsIter(ctx, ListConnectionsRequest{}) { // if err != nil { // return err // } @@ -353,16 +361,13 @@ func (c *internalClient) ListConnections(ctx context.Context, req *ListConnectio // // Callers who need custom pagination logic should use // ListConnections directly. -func (c *internalClient) ListConnectionsIter(ctx context.Context, req *ListConnectionsRequest, opts ...call.Option) iter.Seq2[*ConnectionInfo, error] { +func (c *internalClient) ListConnectionsIter(ctx context.Context, req ListConnectionsRequest, opts ...call.Option) iter.Seq2[*ConnectionInfo, error] { return func(yield func(*ConnectionInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListConnectionsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListConnections(ctx, &pageReq, opts...) + resp, err := c.ListConnections(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -381,8 +386,8 @@ func (c *internalClient) ListConnectionsIter(ctx context.Context, req *ListConne } // Updates the connection that matches the supplied name. -func (c *internalClient) UpdateConnection(ctx context.Context, req *UpdateConnectionRequest, opts ...call.Option) (*ConnectionInfo, error) { - wireReq, err := updateConnectionRequestToWire(req) +func (c *internalClient) UpdateConnection(ctx context.Context, req UpdateConnectionRequest, opts ...call.Option) (*ConnectionInfo, error) { + wireReq, err := updateConnectionRequestToWire(&req) if err != nil { return nil, err } @@ -403,7 +408,11 @@ func (c *internalClient) UpdateConnection(ctx context.Context, req *UpdateConnec } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/connections/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/uc/connections/v1/genhelper.go b/uc/connections/v1/genhelper.go old mode 100755 new mode 100644 index e5af4d2..cb25e33 --- a/uc/connections/v1/genhelper.go +++ b/uc/connections/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/connections/v1/model.go b/uc/connections/v1/model.go old mode 100755 new mode 100644 index db33539..34c1c79 --- a/uc/connections/v1/model.go +++ b/uc/connections/v1/model.go @@ -80,7 +80,11 @@ const ( SecurableType_Credential SecurableType = "CREDENTIAL" SecurableType_ExternalMetadata SecurableType = "EXTERNAL_METADATA" // TODO: [UC-2980] Staging tables aren't full-fleged securables yet. - SecurableType_StagingTable SecurableType = "STAGING_TABLE" + SecurableType_StagingTable SecurableType = "STAGING_TABLE" + SecurableType_Model SecurableType = "MODEL" + SecurableType_ModelService SecurableType = "MODEL_SERVICE" + SecurableType_McpService SecurableType = "MCP_SERVICE" + SecurableType_ModelProviderService SecurableType = "MODEL_PROVIDER_SERVICE" ) type ProvisioningInfo_State string diff --git a/uc/connections/v1/wire.go b/uc/connections/v1/wire.go old mode 100755 new mode 100644 index 7f3c9f3..cfa9451 --- a/uc/connections/v1/wire.go +++ b/uc/connections/v1/wire.go @@ -3,9 +3,55 @@ package connections import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type connectionInfoWire struct { Name *string `json:"name,omitempty"` ConnectionType ConnectionType `json:"connection_type,omitempty"` @@ -18,9 +64,9 @@ type connectionInfoWire struct { CredentialType CredentialType `json:"credential_type,omitempty"` ConnectionId *string `json:"connection_id,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` SecurableType SecurableType `json:"securable_type,omitempty"` ProvisioningInfo *provisioningInfoWire `json:"provisioning_info,omitempty"` @@ -36,6 +82,14 @@ func connectionInfoFromWire(w *connectionInfoWire) (*ConnectionInfo, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "ConnectionInfo.EnvironmentSettings", err) } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ConnectionInfo.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ConnectionInfo.UpdatedAt", err) + } provisioningInfoPublicValue, err := provisioningInfoFromWire(w.ProvisioningInfo) if err != nil { return nil, fmt.Errorf("%s: %w", "ConnectionInfo.ProvisioningInfo", err) @@ -52,9 +106,9 @@ func connectionInfoFromWire(w *connectionInfoWire) (*ConnectionInfo, error) { CredentialType: w.CredentialType, ConnectionId: w.ConnectionId, MetastoreId: w.MetastoreId, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, SecurableType: w.SecurableType, ProvisioningInfo: provisioningInfoPublicValue, @@ -76,9 +130,9 @@ type createConnectionRequestWire struct { CredentialType CredentialType `json:"credential_type,omitempty"` ConnectionId *string `json:"connection_id,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` SecurableType SecurableType `json:"securable_type,omitempty"` ProvisioningInfo *provisioningInfoWire `json:"provisioning_info,omitempty"` @@ -94,6 +148,14 @@ func createConnectionRequestToWire(v *CreateConnectionRequest) (*createConnectio if err != nil { return nil, fmt.Errorf("%s: %w", "CreateConnectionRequest.EnvironmentSettings", err) } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateConnectionRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateConnectionRequest.UpdatedAt", err) + } provisioningInfoWireValue, err := provisioningInfoToWire(v.ProvisioningInfo) if err != nil { return nil, fmt.Errorf("%s: %w", "CreateConnectionRequest.ProvisioningInfo", err) @@ -111,9 +173,9 @@ func createConnectionRequestToWire(v *CreateConnectionRequest) (*createConnectio CredentialType: v.CredentialType, ConnectionId: v.ConnectionId, MetastoreId: v.MetastoreId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, SecurableType: v.SecurableType, ProvisioningInfo: provisioningInfoWireValue, @@ -219,9 +281,9 @@ type updateConnectionRequestWire struct { CredentialType CredentialType `json:"credential_type,omitempty"` ConnectionId *string `json:"connection_id,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` SecurableType SecurableType `json:"securable_type,omitempty"` ProvisioningInfo *provisioningInfoWire `json:"provisioning_info,omitempty"` @@ -237,6 +299,14 @@ func updateConnectionRequestToWire(v *UpdateConnectionRequest) (*updateConnectio if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateConnectionRequest.EnvironmentSettings", err) } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateConnectionRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateConnectionRequest.UpdatedAt", err) + } provisioningInfoWireValue, err := provisioningInfoToWire(v.ProvisioningInfo) if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateConnectionRequest.ProvisioningInfo", err) @@ -255,9 +325,9 @@ func updateConnectionRequestToWire(v *UpdateConnectionRequest) (*updateConnectio CredentialType: v.CredentialType, ConnectionId: v.ConnectionId, MetastoreId: v.MetastoreId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, SecurableType: v.SecurableType, ProvisioningInfo: provisioningInfoWireValue, diff --git a/uc/credentials/CHANGELOG.md b/uc/credentials/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/credentials/CHANGELOG.md +++ b/uc/credentials/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/credentials/go.mod b/uc/credentials/go.mod index b32b145..c790710 100644 --- a/uc/credentials/go.mod +++ b/uc/credentials/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/credentials/internal/version.go b/uc/credentials/internal/version.go index eaa7d0a..037c9b4 100644 --- a/uc/credentials/internal/version.go +++ b/uc/credentials/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-credentials" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/credentials/v1/client.go b/uc/credentials/v1/client.go old mode 100755 new mode 100644 index 6b7c491..37ed5d4 --- a/uc/credentials/v1/client.go +++ b/uc/credentials/v1/client.go @@ -82,8 +82,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // The caller must be a metastore admin and have the `CREATE_STORAGE_CREDENTIAL` // privilege on the metastore. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateAccountsStorageCredential(ctx context.Context, req *AccountsCreateStorageCredentialRequest, opts ...call.Option) (*AccountsCreateStorageCredentialResponse, error) { - wireReq, err := accountsCreateStorageCredentialRequestToWire(req) +func (c *internalClient) CreateAccountsStorageCredential(ctx context.Context, req AccountsCreateStorageCredentialRequest, opts ...call.Option) (*AccountsCreateStorageCredentialResponse, error) { + wireReq, err := accountsCreateStorageCredentialRequestToWire(&req) if err != nil { return nil, err } @@ -107,7 +107,11 @@ func (c *internalClient) CreateAccountsStorageCredential(ctx context.Context, re pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/metastores/") - pb.singleSegment(*req.MetastoreId) + if req.MetastoreId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MetastoreId) + } pb.literal("/storage-credentials") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -157,8 +161,8 @@ func (c *internalClient) CreateAccountsStorageCredential(ctx context.Context, re // Deletes a storage credential from the metastore. The caller must be an owner // of the storage credential. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteAccountsStorageCredential(ctx context.Context, req *AccountsDeleteStorageCredentialRequest, opts ...call.Option) (*AccountsDeleteStorageCredentialResponse, error) { - wireReq, err := accountsDeleteStorageCredentialRequestToWire(req) +func (c *internalClient) DeleteAccountsStorageCredential(ctx context.Context, req AccountsDeleteStorageCredentialRequest, opts ...call.Option) (*AccountsDeleteStorageCredentialResponse, error) { + wireReq, err := accountsDeleteStorageCredentialRequestToWire(&req) if err != nil { return nil, err } @@ -178,9 +182,17 @@ func (c *internalClient) DeleteAccountsStorageCredential(ctx context.Context, re pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/metastores/") - pb.singleSegment(*req.MetastoreId) + if req.MetastoreId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MetastoreId) + } pb.literal("/storage-credentials/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "force", wireReq.Force); err != nil { @@ -226,7 +238,7 @@ func (c *internalClient) DeleteAccountsStorageCredential(ctx context.Context, re // admin, the owner of the storage credential, or have a level of privilege on // the storage credential. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetAccountsStorageCredential(ctx context.Context, req *AccountsGetStorageCredentialRequest, opts ...call.Option) (*AccountsGetStorageCredentialResponse, error) { +func (c *internalClient) GetAccountsStorageCredential(ctx context.Context, req AccountsGetStorageCredentialRequest, opts ...call.Option) (*AccountsGetStorageCredentialResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -243,9 +255,17 @@ func (c *internalClient) GetAccountsStorageCredential(ctx context.Context, req * pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/metastores/") - pb.singleSegment(*req.MetastoreId) + if req.MetastoreId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MetastoreId) + } pb.literal("/storage-credentials/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -293,7 +313,7 @@ func (c *internalClient) GetAccountsStorageCredential(ctx context.Context, req * // Gets a list of all storage credentials that have been assigned to given // metastore. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListAccountsStorageCredentials(ctx context.Context, req *AccountsListStorageCredentialsRequest, opts ...call.Option) (*AccountsListStorageCredentialsResponse, error) { +func (c *internalClient) ListAccountsStorageCredentials(ctx context.Context, req AccountsListStorageCredentialsRequest, opts ...call.Option) (*AccountsListStorageCredentialsResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -310,7 +330,11 @@ func (c *internalClient) ListAccountsStorageCredentials(ctx context.Context, req pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/metastores/") - pb.singleSegment(*req.MetastoreId) + if req.MetastoreId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MetastoreId) + } pb.literal("/storage-credentials") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -360,8 +384,8 @@ func (c *internalClient) ListAccountsStorageCredentials(ctx context.Context, req // of the storage credential. If the caller is a metastore admin, only the // **owner** credential can be changed. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdateAccountsStorageCredential(ctx context.Context, req *AccountsUpdateStorageCredentialRequest, opts ...call.Option) (*AccountsUpdateStorageCredentialResponse, error) { - wireReq, err := accountsUpdateStorageCredentialRequestToWire(req) +func (c *internalClient) UpdateAccountsStorageCredential(ctx context.Context, req AccountsUpdateStorageCredentialRequest, opts ...call.Option) (*AccountsUpdateStorageCredentialResponse, error) { + wireReq, err := accountsUpdateStorageCredentialRequestToWire(&req) if err != nil { return nil, err } @@ -385,9 +409,17 @@ func (c *internalClient) UpdateAccountsStorageCredential(ctx context.Context, re pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/metastores/") - pb.singleSegment(*req.MetastoreId) + if req.MetastoreId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MetastoreId) + } pb.literal("/storage-credentials/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -439,8 +471,8 @@ func (c *internalClient) UpdateAccountsStorageCredential(ctx context.Context, re // The caller must be a metastore admin or have the metastore privilege // **CREATE_STORAGE_CREDENTIAL** for storage credentials, or // **CREATE_SERVICE_CREDENTIAL** for service credentials. -func (c *internalClient) CreateCredential(ctx context.Context, req *CreateCredentialRequest, opts ...call.Option) (*StorageCredentialInfo, error) { - wireReq, err := createCredentialRequestToWire(req) +func (c *internalClient) CreateCredential(ctx context.Context, req CreateCredentialRequest, opts ...call.Option) (*StorageCredentialInfo, error) { + wireReq, err := createCredentialRequestToWire(&req) if err != nil { return nil, err } @@ -508,8 +540,8 @@ func (c *internalClient) CreateCredential(ctx context.Context, req *CreateCreden // // The caller must be a metastore admin or have the // **CREATE_STORAGE_CREDENTIAL** privilege on the metastore. -func (c *internalClient) CreateStorageCredential(ctx context.Context, req *CreateStorageCredentialRequest, opts ...call.Option) (*StorageCredentialInfo, error) { - wireReq, err := createStorageCredentialRequestToWire(req) +func (c *internalClient) CreateStorageCredential(ctx context.Context, req CreateStorageCredentialRequest, opts ...call.Option) (*StorageCredentialInfo, error) { + wireReq, err := createStorageCredentialRequestToWire(&req) if err != nil { return nil, err } @@ -575,8 +607,8 @@ func (c *internalClient) CreateStorageCredential(ctx context.Context, req *Creat // Deletes a service or storage credential from the metastore. The caller must // be an owner of the credential. -func (c *internalClient) DeleteCredential(ctx context.Context, req *DeleteCredentialRequest, opts ...call.Option) (*DeleteCredentialResponse, error) { - wireReq, err := deleteCredentialRequestToWire(req) +func (c *internalClient) DeleteCredential(ctx context.Context, req DeleteCredentialRequest, opts ...call.Option) (*DeleteCredentialResponse, error) { + wireReq, err := deleteCredentialRequestToWire(&req) if err != nil { return nil, err } @@ -593,7 +625,11 @@ func (c *internalClient) DeleteCredential(ctx context.Context, req *DeleteCreden } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/credentials/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "force", wireReq.Force); err != nil { @@ -637,8 +673,8 @@ func (c *internalClient) DeleteCredential(ctx context.Context, req *DeleteCreden // Deletes a storage credential from the metastore. The caller must be an owner // of the storage credential. -func (c *internalClient) DeleteStorageCredential(ctx context.Context, req *DeleteStorageCredentialRequest, opts ...call.Option) (*DeleteStorageCredentialResponse, error) { - wireReq, err := deleteStorageCredentialRequestToWire(req) +func (c *internalClient) DeleteStorageCredential(ctx context.Context, req DeleteStorageCredentialRequest, opts ...call.Option) (*DeleteStorageCredentialResponse, error) { + wireReq, err := deleteStorageCredentialRequestToWire(&req) if err != nil { return nil, err } @@ -655,7 +691,11 @@ func (c *internalClient) DeleteStorageCredential(ctx context.Context, req *Delet } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/storage-credentials/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "force", wireReq.Force); err != nil { @@ -707,8 +747,8 @@ func (c *internalClient) DeleteStorageCredential(ctx context.Context, req *Delet // owners. For requests on existing external tables, the caller must also have // the **EXTERNAL_USE_SCHEMA** privilege on the parent schema; this privilege // can only be granted by catalog owners. -func (c *internalClient) GenerateTemporaryPathCredential(ctx context.Context, req *GenerateTemporaryPathCredentialRequest, opts ...call.Option) (*GenerateTemporaryPathCredentialResponse, error) { - wireReq, err := generateTemporaryPathCredentialRequestToWire(req) +func (c *internalClient) GenerateTemporaryPathCredential(ctx context.Context, req GenerateTemporaryPathCredentialRequest, opts ...call.Option) (*GenerateTemporaryPathCredentialResponse, error) { + wireReq, err := generateTemporaryPathCredentialRequestToWire(&req) if err != nil { return nil, err } @@ -775,8 +815,8 @@ func (c *internalClient) GenerateTemporaryPathCredential(ctx context.Context, re // Returns a set of temporary credentials generated using the specified service // credential. The caller must be a metastore admin or have the metastore // privilege **ACCESS** on the service credential. -func (c *internalClient) GenerateTemporaryServiceCredential(ctx context.Context, req *GenerateTemporaryServiceCredentialRequest, opts ...call.Option) (*TemporaryCredentials, error) { - wireReq, err := generateTemporaryServiceCredentialRequestToWire(req) +func (c *internalClient) GenerateTemporaryServiceCredential(ctx context.Context, req GenerateTemporaryServiceCredentialRequest, opts ...call.Option) (*TemporaryCredentials, error) { + wireReq, err := generateTemporaryServiceCredentialRequestToWire(&req) if err != nil { return nil, err } @@ -845,8 +885,8 @@ func (c *internalClient) GenerateTemporaryServiceCredential(ctx context.Context, // (default false). The caller must have the **EXTERNAL_USE_SCHEMA** privilege // on the parent schema and this privilege can only be granted by catalog // owners. -func (c *internalClient) GenerateTemporaryTableCredential(ctx context.Context, req *GenerateTemporaryTableCredentialRequest, opts ...call.Option) (*GenerateTemporaryTableCredentialResponse, error) { - wireReq, err := generateTemporaryTableCredentialRequestToWire(req) +func (c *internalClient) GenerateTemporaryTableCredential(ctx context.Context, req GenerateTemporaryTableCredentialRequest, opts ...call.Option) (*GenerateTemporaryTableCredentialResponse, error) { + wireReq, err := generateTemporaryTableCredentialRequestToWire(&req) if err != nil { return nil, err } @@ -915,8 +955,8 @@ func (c *internalClient) GenerateTemporaryTableCredential(ctx context.Context, r // (default false). The caller must have the **EXTERNAL_USE_SCHEMA** privilege // on the parent schema and this privilege can only be granted by catalog // owners. -func (c *internalClient) GenerateTemporaryVolumeCredential(ctx context.Context, req *GenerateTemporaryVolumeCredentialRequest, opts ...call.Option) (*GenerateTemporaryVolumeCredentialResponse, error) { - wireReq, err := generateTemporaryVolumeCredentialRequestToWire(req) +func (c *internalClient) GenerateTemporaryVolumeCredential(ctx context.Context, req GenerateTemporaryVolumeCredentialRequest, opts ...call.Option) (*GenerateTemporaryVolumeCredentialResponse, error) { + wireReq, err := generateTemporaryVolumeCredentialRequestToWire(&req) if err != nil { return nil, err } @@ -983,7 +1023,7 @@ func (c *internalClient) GenerateTemporaryVolumeCredential(ctx context.Context, // Gets a service or storage credential from the metastore. The caller must be a // metastore admin, the owner of the credential, or have any permission on the // credential. -func (c *internalClient) GetCredential(ctx context.Context, req *GetCredentialRequest, opts ...call.Option) (*StorageCredentialInfo, error) { +func (c *internalClient) GetCredential(ctx context.Context, req GetCredentialRequest, opts ...call.Option) (*StorageCredentialInfo, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -997,7 +1037,11 @@ func (c *internalClient) GetCredential(ctx context.Context, req *GetCredentialRe } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/credentials/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1045,7 +1089,7 @@ func (c *internalClient) GetCredential(ctx context.Context, req *GetCredentialRe // Gets a storage credential from the metastore. The caller must be a metastore // admin, the owner of the storage credential, or have some permission on the // storage credential. -func (c *internalClient) GetStorageCredential(ctx context.Context, req *GetStorageCredentialRequest, opts ...call.Option) (*StorageCredentialInfo, error) { +func (c *internalClient) GetStorageCredential(ctx context.Context, req GetStorageCredentialRequest, opts ...call.Option) (*StorageCredentialInfo, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1059,7 +1103,11 @@ func (c *internalClient) GetStorageCredential(ctx context.Context, req *GetStora } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/storage-credentials/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1115,8 +1163,8 @@ func (c *internalClient) GetStorageCredential(ctx context.Context, req *GetStora // results while still providing a next_page_token. Clients must continue // reading pages until next_page_token is absent, which is the only indication // that the end of results has been reached. -func (c *internalClient) ListCredentials(ctx context.Context, req *ListCredentialsRequest, opts ...call.Option) (*ListCredentialsRequest_Response, error) { - wireReq, err := listCredentialsRequestToWire(req) +func (c *internalClient) ListCredentials(ctx context.Context, req ListCredentialsRequest, opts ...call.Option) (*ListCredentialsRequest_Response, error) { + wireReq, err := listCredentialsRequestToWire(&req) if err != nil { return nil, err } @@ -1189,7 +1237,7 @@ func (c *internalClient) ListCredentials(ctx context.Context, req *ListCredentia // // For example: // -// for item, err := range c.ListCredentialsIter(ctx, &ListCredentialsRequest{}) { +// for item, err := range c.ListCredentialsIter(ctx, ListCredentialsRequest{}) { // if err != nil { // return err // } @@ -1201,16 +1249,13 @@ func (c *internalClient) ListCredentials(ctx context.Context, req *ListCredentia // // Callers who need custom pagination logic should use // ListCredentials directly. -func (c *internalClient) ListCredentialsIter(ctx context.Context, req *ListCredentialsRequest, opts ...call.Option) iter.Seq2[*CredentialInfo, error] { +func (c *internalClient) ListCredentialsIter(ctx context.Context, req ListCredentialsRequest, opts ...call.Option) iter.Seq2[*CredentialInfo, error] { return func(yield func(*CredentialInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListCredentialsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListCredentials(ctx, &pageReq, opts...) + resp, err := c.ListCredentials(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1241,8 +1286,8 @@ func (c *internalClient) ListCredentialsIter(ctx context.Context, req *ListCrede // contain zero results while still providing a next_page_token. Clients must // continue reading pages until next_page_token is absent, which is the only // indication that the end of results has been reached. -func (c *internalClient) ListStorageCredentials(ctx context.Context, req *ListStorageCredentialsRequest, opts ...call.Option) (*ListStorageCredentialsResponse, error) { - wireReq, err := listStorageCredentialsRequestToWire(req) +func (c *internalClient) ListStorageCredentials(ctx context.Context, req ListStorageCredentialsRequest, opts ...call.Option) (*ListStorageCredentialsResponse, error) { + wireReq, err := listStorageCredentialsRequestToWire(&req) if err != nil { return nil, err } @@ -1315,7 +1360,7 @@ func (c *internalClient) ListStorageCredentials(ctx context.Context, req *ListSt // // For example: // -// for item, err := range c.ListStorageCredentialsIter(ctx, &ListStorageCredentialsRequest{}) { +// for item, err := range c.ListStorageCredentialsIter(ctx, ListStorageCredentialsRequest{}) { // if err != nil { // return err // } @@ -1327,16 +1372,13 @@ func (c *internalClient) ListStorageCredentials(ctx context.Context, req *ListSt // // Callers who need custom pagination logic should use // ListStorageCredentials directly. -func (c *internalClient) ListStorageCredentialsIter(ctx context.Context, req *ListStorageCredentialsRequest, opts ...call.Option) iter.Seq2[*StorageCredentialInfo, error] { +func (c *internalClient) ListStorageCredentialsIter(ctx context.Context, req ListStorageCredentialsRequest, opts ...call.Option) iter.Seq2[*StorageCredentialInfo, error] { return func(yield func(*StorageCredentialInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListStorageCredentialsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListStorageCredentials(ctx, &pageReq, opts...) + resp, err := c.ListStorageCredentials(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1359,8 +1401,8 @@ func (c *internalClient) ListStorageCredentialsIter(ctx context.Context, req *Li // The caller must be the owner of the credential or a metastore admin or have // the `MANAGE` permission. If the caller is a metastore admin, only the // __owner__ field can be changed. -func (c *internalClient) UpdateCredential(ctx context.Context, req *UpdateCredentialRequest, opts ...call.Option) (*StorageCredentialInfo, error) { - wireReq, err := updateCredentialRequestToWire(req) +func (c *internalClient) UpdateCredential(ctx context.Context, req UpdateCredentialRequest, opts ...call.Option) (*StorageCredentialInfo, error) { + wireReq, err := updateCredentialRequestToWire(&req) if err != nil { return nil, err } @@ -1381,7 +1423,11 @@ func (c *internalClient) UpdateCredential(ctx context.Context, req *UpdateCreden } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/credentials/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1431,8 +1477,8 @@ func (c *internalClient) UpdateCredential(ctx context.Context, req *UpdateCreden // // The caller must be the owner of the storage credential or a metastore admin. // If the caller is a metastore admin, only the **owner** field can be changed. -func (c *internalClient) UpdateStorageCredential(ctx context.Context, req *UpdateStorageCredentialRequest, opts ...call.Option) (*StorageCredentialInfo, error) { - wireReq, err := updateStorageCredentialRequestToWire(req) +func (c *internalClient) UpdateStorageCredential(ctx context.Context, req UpdateStorageCredentialRequest, opts ...call.Option) (*StorageCredentialInfo, error) { + wireReq, err := updateStorageCredentialRequestToWire(&req) if err != nil { return nil, err } @@ -1453,7 +1499,11 @@ func (c *internalClient) UpdateStorageCredential(ctx context.Context, req *Updat } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/storage-credentials/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1514,8 +1564,8 @@ func (c *internalClient) UpdateStorageCredential(ctx context.Context, req *Updat // The caller must be a metastore admin or the credential owner or have the // required permission on the metastore and the credential (e.g., // **CREATE_EXTERNAL_LOCATION** when purpose is **STORAGE**). -func (c *internalClient) ValidateCredential(ctx context.Context, req *ValidateCredentialRequest, opts ...call.Option) (*ValidateCredentialResponse, error) { - wireReq, err := validateCredentialRequestToWire(req) +func (c *internalClient) ValidateCredential(ctx context.Context, req ValidateCredentialRequest, opts ...call.Option) (*ValidateCredentialResponse, error) { + wireReq, err := validateCredentialRequestToWire(&req) if err != nil { return nil, err } @@ -1591,8 +1641,8 @@ func (c *internalClient) ValidateCredential(ctx context.Context, req *ValidateCr // The caller must be a metastore admin or the storage credential owner or have // the **CREATE_EXTERNAL_LOCATION** privilege on the metastore and the storage // credential. -func (c *internalClient) ValidateStorageCredential(ctx context.Context, req *ValidateStorageCredentialRequest, opts ...call.Option) (*ValidateStorageCredentialResponse, error) { - wireReq, err := validateStorageCredentialRequestToWire(req) +func (c *internalClient) ValidateStorageCredential(ctx context.Context, req ValidateStorageCredentialRequest, opts ...call.Option) (*ValidateStorageCredentialResponse, error) { + wireReq, err := validateStorageCredentialRequestToWire(&req) if err != nil { return nil, err } @@ -1671,8 +1721,8 @@ func (c *internalClient) ValidateStorageCredential(ctx context.Context, req *Val // // [Create a new workspace using the Account API]: http://docs.databricks.com/administration-guide/account-api/new-workspace.html // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateCredentialsPublic(ctx context.Context, req *CreateCredentialsRequest, opts ...call.Option) (*Credentials, error) { - wireReq, err := createCredentialsRequestToWire(req) +func (c *internalClient) CreateCredentialsPublic(ctx context.Context, req CreateCredentialsRequest, opts ...call.Option) (*Credentials, error) { + wireReq, err := createCredentialsRequestToWire(&req) if err != nil { return nil, err } @@ -1745,7 +1795,7 @@ func (c *internalClient) CreateCredentialsPublic(ctx context.Context, req *Creat // specified by ID. You cannot delete a credential that is associated with any // workspace. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteCredentialsPublic(ctx context.Context, req *DeleteCredentialsRequest, opts ...call.Option) (*Credentials, error) { +func (c *internalClient) DeleteCredentialsPublic(ctx context.Context, req DeleteCredentialsRequest, opts ...call.Option) (*Credentials, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1762,7 +1812,11 @@ func (c *internalClient) DeleteCredentialsPublic(ctx context.Context, req *Delet pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/credentials/") - pb.singleSegment(*req.CredentialsId) + if req.CredentialsId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CredentialsId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1810,7 +1864,7 @@ func (c *internalClient) DeleteCredentialsPublic(ctx context.Context, req *Delet // Gets a credential configuration object for an account, both // specified by ID. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetCredentialsPublic(ctx context.Context, req *GetCredentialsRequest, opts ...call.Option) (*Credentials, error) { +func (c *internalClient) GetCredentialsPublic(ctx context.Context, req GetCredentialsRequest, opts ...call.Option) (*Credentials, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1827,7 +1881,11 @@ func (c *internalClient) GetCredentialsPublic(ctx context.Context, req *GetCrede pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/credentials/") - pb.singleSegment(*req.CredentialsId) + if req.CredentialsId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CredentialsId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1875,7 +1933,7 @@ func (c *internalClient) GetCredentialsPublic(ctx context.Context, req *GetCrede // List credential configuration objects for an account, specified // by ID. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListCredentialsPublic(ctx context.Context, req *ListCredentialsPublicRequest, opts ...call.Option) (*ListCredentialsResponse, error) { +func (c *internalClient) ListCredentialsPublic(ctx context.Context, req ListCredentialsPublicRequest, opts ...call.Option) (*ListCredentialsResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") diff --git a/uc/credentials/v1/genhelper.go b/uc/credentials/v1/genhelper.go old mode 100755 new mode 100644 index 8aeef03..9ca1482 --- a/uc/credentials/v1/genhelper.go +++ b/uc/credentials/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/credentials/v1/wire.go b/uc/credentials/v1/wire.go old mode 100755 new mode 100644 index 3285290..0e2f78d --- a/uc/credentials/v1/wire.go +++ b/uc/credentials/v1/wire.go @@ -3,9 +3,55 @@ package credentials import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type accountsCreateStorageCredentialRequestWire struct { AccountId *string `json:"account_id,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` @@ -343,9 +389,9 @@ type createAccountsStorageCredentialWire struct { Owner *string `json:"owner,omitempty"` Id *string `json:"id,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` UsedForManagedStorage *bool `json:"used_for_managed_storage,omitempty"` FullName *string `json:"full_name,omitempty"` @@ -356,6 +402,14 @@ func createAccountsStorageCredentialToWire(v *CreateAccountsStorageCredential) ( if v == nil { return nil, nil } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateAccountsStorageCredential.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateAccountsStorageCredential.UpdatedAt", err) + } var credentialAwsIamRoleWire *awsIamRoleWire var credentialAzureServicePrincipalWire *azureServicePrincipalWire var credentialGcpServiceAccountKeyWire *gcpServiceAccountKeyWire @@ -428,9 +482,9 @@ func createAccountsStorageCredentialToWire(v *CreateAccountsStorageCredential) ( Owner: v.Owner, Id: v.Id, MetastoreId: v.MetastoreId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, UsedForManagedStorage: v.UsedForManagedStorage, FullName: v.FullName, @@ -479,9 +533,9 @@ type createCredentialRequestWire struct { Owner *string `json:"owner,omitempty"` Id *string `json:"id,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` UsedForManagedStorage *bool `json:"used_for_managed_storage,omitempty"` FullName *string `json:"full_name,omitempty"` @@ -492,6 +546,14 @@ func createCredentialRequestToWire(v *CreateCredentialRequest) (*createCredentia if v == nil { return nil, nil } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateCredentialRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateCredentialRequest.UpdatedAt", err) + } var credentialAwsIamRoleWire *awsIamRoleWire var credentialAzureServicePrincipalWire *azureServicePrincipalWire var credentialGcpServiceAccountKeyWire *gcpServiceAccountKeyWire @@ -565,9 +627,9 @@ func createCredentialRequestToWire(v *CreateCredentialRequest) (*createCredentia Owner: v.Owner, Id: v.Id, MetastoreId: v.MetastoreId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, UsedForManagedStorage: v.UsedForManagedStorage, FullName: v.FullName, @@ -620,9 +682,9 @@ type createStorageCredentialRequestWire struct { Owner *string `json:"owner,omitempty"` Id *string `json:"id,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` UsedForManagedStorage *bool `json:"used_for_managed_storage,omitempty"` FullName *string `json:"full_name,omitempty"` @@ -633,6 +695,14 @@ func createStorageCredentialRequestToWire(v *CreateStorageCredentialRequest) (*c if v == nil { return nil, nil } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateStorageCredentialRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateStorageCredentialRequest.UpdatedAt", err) + } var credentialAwsIamRoleWire *awsIamRoleWire var credentialAzureServicePrincipalWire *azureServicePrincipalWire var credentialGcpServiceAccountKeyWire *gcpServiceAccountKeyWire @@ -706,9 +776,9 @@ func createStorageCredentialRequestToWire(v *CreateStorageCredentialRequest) (*c Owner: v.Owner, Id: v.Id, MetastoreId: v.MetastoreId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, UsedForManagedStorage: v.UsedForManagedStorage, FullName: v.FullName, @@ -729,9 +799,9 @@ type credentialInfoWire struct { Owner *string `json:"owner,omitempty"` Id *string `json:"id,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` UsedForManagedStorage *bool `json:"used_for_managed_storage,omitempty"` FullName *string `json:"full_name,omitempty"` @@ -764,6 +834,14 @@ func credentialInfoFromWire(w *credentialInfoWire) (*CredentialInfo, error) { if credentialMembers > 1 { return nil, fmt.Errorf("%s: multiple oneof members set", "CredentialInfo.Credential") } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CredentialInfo.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CredentialInfo.UpdatedAt", err) + } var credentialSelection isCredentialInfo_Credential switch { case w.AwsIamRole != nil: @@ -810,9 +888,9 @@ func credentialInfoFromWire(w *credentialInfoWire) (*CredentialInfo, error) { Owner: w.Owner, Id: w.Id, MetastoreId: w.MetastoreId, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, UsedForManagedStorage: w.UsedForManagedStorage, FullName: w.FullName, @@ -826,7 +904,7 @@ type credentialsWire struct { AccountId *string `json:"account_id,omitempty"` AwsCredentials *awsCredentialsWire `json:"aws_credentials,omitempty"` CredentialsName *string `json:"credentials_name,omitempty"` - CreationTime *int64 `json:"creation_time,omitempty"` + CreationTime *wireInt64 `json:"creation_time,omitempty"` } func credentialsFromWire(w *credentialsWire) (*Credentials, error) { @@ -840,6 +918,10 @@ func credentialsFromWire(w *credentialsWire) (*Credentials, error) { if cloudCredentialsMembers > 1 { return nil, fmt.Errorf("%s: multiple oneof members set", "Credentials.CloudCredentials") } + creationTimePublicValue, err := int64FromWire(w.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Credentials.CreationTime", err) + } var cloudCredentialsSelection isCredentials_CloudCredentials switch { case w.AwsCredentials != nil: @@ -853,7 +935,7 @@ func credentialsFromWire(w *credentialsWire) (*Credentials, error) { CredentialsId: w.CredentialsId, AccountId: w.AccountId, CredentialsName: w.CredentialsName, - CreationTime: w.CreationTime, + CreationTime: creationTimePublicValue, CloudCredentials: cloudCredentialsSelection, }, nil } @@ -980,7 +1062,7 @@ type generateTemporaryPathCredentialResponseWire struct { GcpOauthToken *gcpOauthTokenWire `json:"gcp_oauth_token,omitempty"` AzureAad *azureActiveDirectoryTokenWire `json:"azure_aad,omitempty"` R2TempCredentials *r2CredentialsWire `json:"r2_temp_credentials,omitempty"` - ExpirationTime *int64 `json:"expiration_time,omitempty"` + ExpirationTime *wireInt64 `json:"expiration_time,omitempty"` Url *string `json:"url,omitempty"` } @@ -1007,6 +1089,10 @@ func generateTemporaryPathCredentialResponseFromWire(w *generateTemporaryPathCre if credentialsMembers > 1 { return nil, fmt.Errorf("%s: multiple oneof members set", "GenerateTemporaryPathCredentialResponse.Credentials") } + expirationTimePublicValue, err := int64FromWire(w.ExpirationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenerateTemporaryPathCredentialResponse.ExpirationTime", err) + } var credentialsSelection isGenerateTemporaryPathCredentialResponse_Credentials switch { case w.AwsTempCredentials != nil: @@ -1041,7 +1127,7 @@ func generateTemporaryPathCredentialResponseFromWire(w *generateTemporaryPathCre credentialsSelection = &GenerateTemporaryPathCredentialResponse_Credentials_R2TempCredentials{R2TempCredentials: *credentialsR2TempCredentialsConverted} } return &GenerateTemporaryPathCredentialResponse{ - ExpirationTime: w.ExpirationTime, + ExpirationTime: expirationTimePublicValue, Url: w.Url, Credentials: credentialsSelection, }, nil @@ -1134,7 +1220,7 @@ type generateTemporaryTableCredentialResponseWire struct { GcpOauthToken *gcpOauthTokenWire `json:"gcp_oauth_token,omitempty"` AzureAad *azureActiveDirectoryTokenWire `json:"azure_aad,omitempty"` R2TempCredentials *r2CredentialsWire `json:"r2_temp_credentials,omitempty"` - ExpirationTime *int64 `json:"expiration_time,omitempty"` + ExpirationTime *wireInt64 `json:"expiration_time,omitempty"` Url *string `json:"url,omitempty"` } @@ -1161,6 +1247,10 @@ func generateTemporaryTableCredentialResponseFromWire(w *generateTemporaryTableC if credentialsMembers > 1 { return nil, fmt.Errorf("%s: multiple oneof members set", "GenerateTemporaryTableCredentialResponse.Credentials") } + expirationTimePublicValue, err := int64FromWire(w.ExpirationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenerateTemporaryTableCredentialResponse.ExpirationTime", err) + } var credentialsSelection isGenerateTemporaryTableCredentialResponse_Credentials switch { case w.AwsTempCredentials != nil: @@ -1195,7 +1285,7 @@ func generateTemporaryTableCredentialResponseFromWire(w *generateTemporaryTableC credentialsSelection = &GenerateTemporaryTableCredentialResponse_Credentials_R2TempCredentials{R2TempCredentials: *credentialsR2TempCredentialsConverted} } return &GenerateTemporaryTableCredentialResponse{ - ExpirationTime: w.ExpirationTime, + ExpirationTime: expirationTimePublicValue, Url: w.Url, Credentials: credentialsSelection, }, nil @@ -1222,7 +1312,7 @@ type generateTemporaryVolumeCredentialResponseWire struct { GcpOauthToken *gcpOauthTokenWire `json:"gcp_oauth_token,omitempty"` AzureAad *azureActiveDirectoryTokenWire `json:"azure_aad,omitempty"` R2TempCredentials *r2CredentialsWire `json:"r2_temp_credentials,omitempty"` - ExpirationTime *int64 `json:"expiration_time,omitempty"` + ExpirationTime *wireInt64 `json:"expiration_time,omitempty"` Url *string `json:"url,omitempty"` } @@ -1249,6 +1339,10 @@ func generateTemporaryVolumeCredentialResponseFromWire(w *generateTemporaryVolum if credentialsMembers > 1 { return nil, fmt.Errorf("%s: multiple oneof members set", "GenerateTemporaryVolumeCredentialResponse.Credentials") } + expirationTimePublicValue, err := int64FromWire(w.ExpirationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GenerateTemporaryVolumeCredentialResponse.ExpirationTime", err) + } var credentialsSelection isGenerateTemporaryVolumeCredentialResponse_Credentials switch { case w.AwsTempCredentials != nil: @@ -1283,7 +1377,7 @@ func generateTemporaryVolumeCredentialResponseFromWire(w *generateTemporaryVolum credentialsSelection = &GenerateTemporaryVolumeCredentialResponse_Credentials_R2TempCredentials{R2TempCredentials: *credentialsR2TempCredentialsConverted} } return &GenerateTemporaryVolumeCredentialResponse{ - ExpirationTime: w.ExpirationTime, + ExpirationTime: expirationTimePublicValue, Url: w.Url, Credentials: credentialsSelection, }, nil @@ -1391,9 +1485,9 @@ type storageCredentialInfoWire struct { Owner *string `json:"owner,omitempty"` Id *string `json:"id,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` UsedForManagedStorage *bool `json:"used_for_managed_storage,omitempty"` FullName *string `json:"full_name,omitempty"` @@ -1426,6 +1520,14 @@ func storageCredentialInfoFromWire(w *storageCredentialInfoWire) (*StorageCreden if credentialMembers > 1 { return nil, fmt.Errorf("%s: multiple oneof members set", "StorageCredentialInfo.Credential") } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "StorageCredentialInfo.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "StorageCredentialInfo.UpdatedAt", err) + } var credentialSelection isStorageCredentialInfo_Credential switch { case w.AwsIamRole != nil: @@ -1472,9 +1574,9 @@ func storageCredentialInfoFromWire(w *storageCredentialInfoWire) (*StorageCreden Owner: w.Owner, Id: w.Id, MetastoreId: w.MetastoreId, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, UsedForManagedStorage: w.UsedForManagedStorage, FullName: w.FullName, @@ -1508,7 +1610,7 @@ type temporaryCredentialsWire struct { GcpOauthToken *gcpOauthTokenWire `json:"gcp_oauth_token,omitempty"` AzureAad *azureActiveDirectoryTokenWire `json:"azure_aad,omitempty"` R2TempCredentials *r2CredentialsWire `json:"r2_temp_credentials,omitempty"` - ExpirationTime *int64 `json:"expiration_time,omitempty"` + ExpirationTime *wireInt64 `json:"expiration_time,omitempty"` Url *string `json:"url,omitempty"` } @@ -1535,6 +1637,10 @@ func temporaryCredentialsFromWire(w *temporaryCredentialsWire) (*TemporaryCreden if credentialsMembers > 1 { return nil, fmt.Errorf("%s: multiple oneof members set", "TemporaryCredentials.Credentials") } + expirationTimePublicValue, err := int64FromWire(w.ExpirationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TemporaryCredentials.ExpirationTime", err) + } var credentialsSelection isTemporaryCredentials_Credentials switch { case w.AwsTempCredentials != nil: @@ -1569,7 +1675,7 @@ func temporaryCredentialsFromWire(w *temporaryCredentialsWire) (*TemporaryCreden credentialsSelection = &TemporaryCredentials_Credentials_R2TempCredentials{R2TempCredentials: *credentialsR2TempCredentialsConverted} } return &TemporaryCredentials{ - ExpirationTime: w.ExpirationTime, + ExpirationTime: expirationTimePublicValue, Url: w.Url, Credentials: credentialsSelection, }, nil @@ -1588,9 +1694,9 @@ type updateAccountsStorageCredentialWire struct { Owner *string `json:"owner,omitempty"` Id *string `json:"id,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` UsedForManagedStorage *bool `json:"used_for_managed_storage,omitempty"` FullName *string `json:"full_name,omitempty"` @@ -1601,6 +1707,14 @@ func updateAccountsStorageCredentialToWire(v *UpdateAccountsStorageCredential) ( if v == nil { return nil, nil } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateAccountsStorageCredential.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateAccountsStorageCredential.UpdatedAt", err) + } var credentialAwsIamRoleWire *awsIamRoleWire var credentialAzureServicePrincipalWire *azureServicePrincipalWire var credentialGcpServiceAccountKeyWire *gcpServiceAccountKeyWire @@ -1673,9 +1787,9 @@ func updateAccountsStorageCredentialToWire(v *UpdateAccountsStorageCredential) ( Owner: v.Owner, Id: v.Id, MetastoreId: v.MetastoreId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, UsedForManagedStorage: v.UsedForManagedStorage, FullName: v.FullName, @@ -1700,9 +1814,9 @@ type updateCredentialRequestWire struct { Owner *string `json:"owner,omitempty"` Id *string `json:"id,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` UsedForManagedStorage *bool `json:"used_for_managed_storage,omitempty"` FullName *string `json:"full_name,omitempty"` @@ -1713,6 +1827,14 @@ func updateCredentialRequestToWire(v *UpdateCredentialRequest) (*updateCredentia if v == nil { return nil, nil } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateCredentialRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateCredentialRequest.UpdatedAt", err) + } var credentialAwsIamRoleWire *awsIamRoleWire var credentialAzureServicePrincipalWire *azureServicePrincipalWire var credentialGcpServiceAccountKeyWire *gcpServiceAccountKeyWire @@ -1789,9 +1911,9 @@ func updateCredentialRequestToWire(v *UpdateCredentialRequest) (*updateCredentia Owner: v.Owner, Id: v.Id, MetastoreId: v.MetastoreId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, UsedForManagedStorage: v.UsedForManagedStorage, FullName: v.FullName, @@ -1816,9 +1938,9 @@ type updateStorageCredentialRequestWire struct { Owner *string `json:"owner,omitempty"` Id *string `json:"id,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` UsedForManagedStorage *bool `json:"used_for_managed_storage,omitempty"` FullName *string `json:"full_name,omitempty"` @@ -1829,6 +1951,14 @@ func updateStorageCredentialRequestToWire(v *UpdateStorageCredentialRequest) (*u if v == nil { return nil, nil } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateStorageCredentialRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateStorageCredentialRequest.UpdatedAt", err) + } var credentialAwsIamRoleWire *awsIamRoleWire var credentialAzureServicePrincipalWire *azureServicePrincipalWire var credentialGcpServiceAccountKeyWire *gcpServiceAccountKeyWire @@ -1905,9 +2035,9 @@ func updateStorageCredentialRequestToWire(v *UpdateStorageCredentialRequest) (*u Owner: v.Owner, Id: v.Id, MetastoreId: v.MetastoreId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, UsedForManagedStorage: v.UsedForManagedStorage, FullName: v.FullName, diff --git a/uc/entitytagassignments/CHANGELOG.md b/uc/entitytagassignments/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/entitytagassignments/CHANGELOG.md +++ b/uc/entitytagassignments/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/entitytagassignments/go.mod b/uc/entitytagassignments/go.mod index 784ceb5..b811b1e 100644 --- a/uc/entitytagassignments/go.mod +++ b/uc/entitytagassignments/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/entitytagassignments/internal/version.go b/uc/entitytagassignments/internal/version.go index 0197cdc..e6c1850 100644 --- a/uc/entitytagassignments/internal/version.go +++ b/uc/entitytagassignments/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-entitytagassignments" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/entitytagassignments/v1/client.go b/uc/entitytagassignments/v1/client.go old mode 100755 new mode 100644 index 6a7c465..82ea603 --- a/uc/entitytagassignments/v1/client.go +++ b/uc/entitytagassignments/v1/client.go @@ -85,8 +85,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // permissions]. // // [Manage tag policy permissions]: https://docs.databricks.com/aws/en/admin/tag-policies/manage-permissions -func (c *internalClient) CreateEntityTagAssignment(ctx context.Context, req *CreateEntityTagAssignmentRequest, opts ...call.Option) (*EntityTagAssignment, error) { - wireReq, err := createEntityTagAssignmentRequestToWire(req) +func (c *internalClient) CreateEntityTagAssignment(ctx context.Context, req CreateEntityTagAssignmentRequest, opts ...call.Option) (*EntityTagAssignment, error) { + wireReq, err := createEntityTagAssignmentRequestToWire(&req) if err != nil { return nil, err } @@ -161,7 +161,7 @@ func (c *internalClient) CreateEntityTagAssignment(ctx context.Context, req *Cre // permissions]. // // [Manage tag policy permissions]: https://docs.databricks.com/aws/en/admin/tag-policies/manage-permissions -func (c *internalClient) DeleteEntityTagAssignment(ctx context.Context, req *DeleteEntityTagAssignmentRequest, opts ...call.Option) error { +func (c *internalClient) DeleteEntityTagAssignment(ctx context.Context, req DeleteEntityTagAssignmentRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -175,11 +175,23 @@ func (c *internalClient) DeleteEntityTagAssignment(ctx context.Context, req *Del } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/entity-tag-assignments/") - pb.singleSegment(*req.EntityType) + if req.EntityType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.EntityType) + } pb.literal("/") - pb.singleSegment(*req.EntityName) + if req.EntityName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.EntityName) + } pb.literal("/tags/") - pb.singleSegment(*req.TagKey) + if req.TagKey == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.TagKey) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -216,7 +228,7 @@ func (c *internalClient) DeleteEntityTagAssignment(ctx context.Context, req *Del } // Gets a tag assignment for an Unity Catalog entity by tag key. -func (c *internalClient) GetEntityTagAssignment(ctx context.Context, req *GetEntityTagAssignmentRequest, opts ...call.Option) (*EntityTagAssignment, error) { +func (c *internalClient) GetEntityTagAssignment(ctx context.Context, req GetEntityTagAssignmentRequest, opts ...call.Option) (*EntityTagAssignment, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -230,11 +242,23 @@ func (c *internalClient) GetEntityTagAssignment(ctx context.Context, req *GetEnt } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/entity-tag-assignments/") - pb.singleSegment(*req.EntityType) + if req.EntityType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.EntityType) + } pb.literal("/") - pb.singleSegment(*req.EntityName) + if req.EntityName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.EntityName) + } pb.literal("/tags/") - pb.singleSegment(*req.TagKey) + if req.TagKey == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.TagKey) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -285,8 +309,8 @@ func (c *internalClient) GetEntityTagAssignment(ctx context.Context, req *GetEnt // results while still providing a next_page_token. Clients must continue // reading pages until next_page_token is absent, which is the only indication // that the end of results has been reached. -func (c *internalClient) ListEntityTagAssignments(ctx context.Context, req *ListEntityTagAssignmentsRequest, opts ...call.Option) (*ListEntityTagAssignmentsResponse, error) { - wireReq, err := listEntityTagAssignmentsRequestToWire(req) +func (c *internalClient) ListEntityTagAssignments(ctx context.Context, req ListEntityTagAssignmentsRequest, opts ...call.Option) (*ListEntityTagAssignmentsResponse, error) { + wireReq, err := listEntityTagAssignmentsRequestToWire(&req) if err != nil { return nil, err } @@ -303,9 +327,17 @@ func (c *internalClient) ListEntityTagAssignments(ctx context.Context, req *List } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/entity-tag-assignments/") - pb.singleSegment(*req.EntityType) + if req.EntityType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.EntityType) + } pb.literal("/") - pb.singleSegment(*req.EntityName) + if req.EntityName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.EntityName) + } pb.literal("/tags") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -362,7 +394,7 @@ func (c *internalClient) ListEntityTagAssignments(ctx context.Context, req *List // // For example: // -// for item, err := range c.ListEntityTagAssignmentsIter(ctx, &ListEntityTagAssignmentsRequest{}) { +// for item, err := range c.ListEntityTagAssignmentsIter(ctx, ListEntityTagAssignmentsRequest{}) { // if err != nil { // return err // } @@ -374,16 +406,13 @@ func (c *internalClient) ListEntityTagAssignments(ctx context.Context, req *List // // Callers who need custom pagination logic should use // ListEntityTagAssignments directly. -func (c *internalClient) ListEntityTagAssignmentsIter(ctx context.Context, req *ListEntityTagAssignmentsRequest, opts ...call.Option) iter.Seq2[*EntityTagAssignment, error] { +func (c *internalClient) ListEntityTagAssignmentsIter(ctx context.Context, req ListEntityTagAssignmentsRequest, opts ...call.Option) iter.Seq2[*EntityTagAssignment, error] { return func(yield func(*EntityTagAssignment, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListEntityTagAssignmentsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListEntityTagAssignments(ctx, &pageReq, opts...) + resp, err := c.ListEntityTagAssignments(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -412,8 +441,8 @@ func (c *internalClient) ListEntityTagAssignmentsIter(ctx context.Context, req * // permissions]. // // [Manage tag policy permissions]: https://docs.databricks.com/aws/en/admin/tag-policies/manage-permissions -func (c *internalClient) UpdateEntityTagAssignment(ctx context.Context, req *UpdateEntityTagAssignmentRequest, opts ...call.Option) (*EntityTagAssignment, error) { - wireReq, err := updateEntityTagAssignmentRequestToWire(req) +func (c *internalClient) UpdateEntityTagAssignment(ctx context.Context, req UpdateEntityTagAssignmentRequest, opts ...call.Option) (*EntityTagAssignment, error) { + wireReq, err := updateEntityTagAssignmentRequestToWire(&req) if err != nil { return nil, err } @@ -434,11 +463,23 @@ func (c *internalClient) UpdateEntityTagAssignment(ctx context.Context, req *Upd } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/entity-tag-assignments/") - pb.singleSegment(*req.TagAssignment.EntityType) + if req.TagAssignment == nil || req.TagAssignment.EntityType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.TagAssignment.EntityType) + } pb.literal("/") - pb.singleSegment(*req.TagAssignment.EntityName) + if req.TagAssignment == nil || req.TagAssignment.EntityName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.TagAssignment.EntityName) + } pb.literal("/tags/") - pb.singleSegment(*req.TagAssignment.TagKey) + if req.TagAssignment == nil || req.TagAssignment.TagKey == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.TagAssignment.TagKey) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { diff --git a/uc/entitytagassignments/v1/genhelper.go b/uc/entitytagassignments/v1/genhelper.go old mode 100755 new mode 100644 index 4cf1f13..3c42a34 --- a/uc/entitytagassignments/v1/genhelper.go +++ b/uc/entitytagassignments/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/externallineage/CHANGELOG.md b/uc/externallineage/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/externallineage/CHANGELOG.md +++ b/uc/externallineage/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/externallineage/go.mod b/uc/externallineage/go.mod index 1a1828d..e2c9f8f 100644 --- a/uc/externallineage/go.mod +++ b/uc/externallineage/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/externallineage/internal/version.go b/uc/externallineage/internal/version.go index b18d27f..cf4d1f7 100644 --- a/uc/externallineage/internal/version.go +++ b/uc/externallineage/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-externallineage" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/externallineage/v1/client.go b/uc/externallineage/v1/client.go old mode 100755 new mode 100644 index 9bf2353..91c0a27 --- a/uc/externallineage/v1/client.go +++ b/uc/externallineage/v1/client.go @@ -76,8 +76,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Creates an external lineage relationship between a or external // metadata object and another external metadata object. -func (c *internalClient) CreateExternalLineageRelationship(ctx context.Context, req *CreateExternalLineageRelationshipRequest, opts ...call.Option) (*ExternalLineageRelationship, error) { - wireReq, err := createExternalLineageRelationshipRequestToWire(req) +func (c *internalClient) CreateExternalLineageRelationship(ctx context.Context, req CreateExternalLineageRelationshipRequest, opts ...call.Option) (*ExternalLineageRelationship, error) { + wireReq, err := createExternalLineageRelationshipRequestToWire(&req) if err != nil { return nil, err } @@ -143,8 +143,8 @@ func (c *internalClient) CreateExternalLineageRelationship(ctx context.Context, // Deletes an external lineage relationship between a or external // metadata object and another external metadata object. -func (c *internalClient) DeleteExternalLineageRelationship(ctx context.Context, req *DeleteExternalLineageRelationshipRequest, opts ...call.Option) error { - wireReq, err := deleteExternalLineageRelationshipRequestToWire(req) +func (c *internalClient) DeleteExternalLineageRelationship(ctx context.Context, req DeleteExternalLineageRelationshipRequest, opts ...call.Option) error { + wireReq, err := deleteExternalLineageRelationshipRequestToWire(&req) if err != nil { return err } @@ -199,8 +199,8 @@ func (c *internalClient) DeleteExternalLineageRelationship(ctx context.Context, // Lists external lineage relationships of a object or external // metadata given a supplied direction. -func (c *internalClient) ListExternalLineageRelationships(ctx context.Context, req *ListExternalLineageRelationshipsRequest, opts ...call.Option) (*ListExternalLineageRelationshipsResponse, error) { - wireReq, err := listExternalLineageRelationshipsRequestToWire(req) +func (c *internalClient) ListExternalLineageRelationships(ctx context.Context, req ListExternalLineageRelationshipsRequest, opts ...call.Option) (*ListExternalLineageRelationshipsResponse, error) { + wireReq, err := listExternalLineageRelationshipsRequestToWire(&req) if err != nil { return nil, err } @@ -278,7 +278,7 @@ func (c *internalClient) ListExternalLineageRelationships(ctx context.Context, r // // For example: // -// for item, err := range c.ListExternalLineageRelationshipsIter(ctx, &ListExternalLineageRelationshipsRequest{}) { +// for item, err := range c.ListExternalLineageRelationshipsIter(ctx, ListExternalLineageRelationshipsRequest{}) { // if err != nil { // return err // } @@ -290,16 +290,13 @@ func (c *internalClient) ListExternalLineageRelationships(ctx context.Context, r // // Callers who need custom pagination logic should use // ListExternalLineageRelationships directly. -func (c *internalClient) ListExternalLineageRelationshipsIter(ctx context.Context, req *ListExternalLineageRelationshipsRequest, opts ...call.Option) iter.Seq2[*ExternalLineageInfo, error] { +func (c *internalClient) ListExternalLineageRelationshipsIter(ctx context.Context, req ListExternalLineageRelationshipsRequest, opts ...call.Option) iter.Seq2[*ExternalLineageInfo, error] { return func(yield func(*ExternalLineageInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListExternalLineageRelationshipsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListExternalLineageRelationships(ctx, &pageReq, opts...) + resp, err := c.ListExternalLineageRelationships(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -319,8 +316,8 @@ func (c *internalClient) ListExternalLineageRelationshipsIter(ctx context.Contex // Updates an external lineage relationship between a or external // metadata object and another external metadata object. -func (c *internalClient) UpdateExternalLineageRelationship(ctx context.Context, req *UpdateExternalLineageRelationshipRequest, opts ...call.Option) (*ExternalLineageRelationship, error) { - wireReq, err := updateExternalLineageRelationshipRequestToWire(req) +func (c *internalClient) UpdateExternalLineageRelationship(ctx context.Context, req UpdateExternalLineageRelationshipRequest, opts ...call.Option) (*ExternalLineageRelationship, error) { + wireReq, err := updateExternalLineageRelationshipRequestToWire(&req) if err != nil { return nil, err } diff --git a/uc/externallineage/v1/wire.go b/uc/externallineage/v1/wire.go old mode 100755 new mode 100644 index dd42a37..e45a332 --- a/uc/externallineage/v1/wire.go +++ b/uc/externallineage/v1/wire.go @@ -3,11 +3,57 @@ package externallineage import ( + "bytes" + "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + func fieldMaskToWire[T any](mask *types.FieldMask[T]) *string { if mask == nil { return nil @@ -460,7 +506,7 @@ func lineageFileInfoFromWire(w *lineageFileInfoWire) (*LineageFileInfo, error) { type lineageModelVersionInfoWire struct { ModelName *string `json:"model_name,omitempty"` - Version *int64 `json:"version,omitempty"` + Version *wireInt64 `json:"version,omitempty"` EventTime *types.Time `json:"event_time,omitempty"` } @@ -468,9 +514,13 @@ func lineageModelVersionInfoFromWire(w *lineageModelVersionInfoWire) (*LineageMo if w == nil { return nil, nil } + versionPublicValue, err := int64FromWire(w.Version) + if err != nil { + return nil, fmt.Errorf("%s: %w", "LineageModelVersionInfo.Version", err) + } return &LineageModelVersionInfo{ ModelName: w.ModelName, - Version: w.Version, + Version: versionPublicValue, EventTime: w.EventTime, }, nil } diff --git a/uc/externallocations/CHANGELOG.md b/uc/externallocations/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/externallocations/CHANGELOG.md +++ b/uc/externallocations/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/externallocations/go.mod b/uc/externallocations/go.mod index fa3494d..0ef99c2 100644 --- a/uc/externallocations/go.mod +++ b/uc/externallocations/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/externallocations/internal/version.go b/uc/externallocations/internal/version.go index 6baf02b..8216da1 100644 --- a/uc/externallocations/internal/version.go +++ b/uc/externallocations/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-externallocations" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/externallocations/v1/client.go b/uc/externallocations/v1/client.go old mode 100755 new mode 100644 index 4a1dcdd..17313f4 --- a/uc/externallocations/v1/client.go +++ b/uc/externallocations/v1/client.go @@ -77,8 +77,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Creates a new external location entry in the metastore. The caller must be a // metastore admin or have the **CREATE_EXTERNAL_LOCATION** privilege on both // the metastore and the associated storage credential. -func (c *internalClient) CreateExternalLocation(ctx context.Context, req *CreateExternalLocationRequest, opts ...call.Option) (*ExternalLocationInfo, error) { - wireReq, err := createExternalLocationRequestToWire(req) +func (c *internalClient) CreateExternalLocation(ctx context.Context, req CreateExternalLocationRequest, opts ...call.Option) (*ExternalLocationInfo, error) { + wireReq, err := createExternalLocationRequestToWire(&req) if err != nil { return nil, err } @@ -144,8 +144,8 @@ func (c *internalClient) CreateExternalLocation(ctx context.Context, req *Create // Deletes the specified external location from the metastore. The caller must // be the owner of the external location. -func (c *internalClient) DeleteExternalLocation(ctx context.Context, req *DeleteExternalLocationRequest, opts ...call.Option) (*DeleteExternalLocationResponse, error) { - wireReq, err := deleteExternalLocationRequestToWire(req) +func (c *internalClient) DeleteExternalLocation(ctx context.Context, req DeleteExternalLocationRequest, opts ...call.Option) (*DeleteExternalLocationResponse, error) { + wireReq, err := deleteExternalLocationRequestToWire(&req) if err != nil { return nil, err } @@ -162,7 +162,11 @@ func (c *internalClient) DeleteExternalLocation(ctx context.Context, req *Delete } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/external-locations/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "force", wireReq.Force); err != nil { @@ -207,8 +211,8 @@ func (c *internalClient) DeleteExternalLocation(ctx context.Context, req *Delete // Gets an external location from the metastore. The caller must be either a // metastore admin, the owner of the external location, or a user that has some // privilege on the external location. -func (c *internalClient) GetExternalLocation(ctx context.Context, req *GetExternalLocationRequest, opts ...call.Option) (*ExternalLocationInfo, error) { - wireReq, err := getExternalLocationRequestToWire(req) +func (c *internalClient) GetExternalLocation(ctx context.Context, req GetExternalLocationRequest, opts ...call.Option) (*ExternalLocationInfo, error) { + wireReq, err := getExternalLocationRequestToWire(&req) if err != nil { return nil, err } @@ -225,7 +229,11 @@ func (c *internalClient) GetExternalLocation(ctx context.Context, req *GetExtern } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/external-locations/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "include_browse", wireReq.IncludeBrowse); err != nil { @@ -286,8 +294,8 @@ func (c *internalClient) GetExternalLocation(ctx context.Context, req *GetExtern // contain zero results while still providing a next_page_token. Clients must // continue reading pages until next_page_token is absent, which is the only // indication that the end of results has been reached. -func (c *internalClient) ListExternalLocations(ctx context.Context, req *ListExternalLocationsRequest, opts ...call.Option) (*ListExternalLocationsResponse, error) { - wireReq, err := listExternalLocationsRequestToWire(req) +func (c *internalClient) ListExternalLocations(ctx context.Context, req ListExternalLocationsRequest, opts ...call.Option) (*ListExternalLocationsResponse, error) { + wireReq, err := listExternalLocationsRequestToWire(&req) if err != nil { return nil, err } @@ -363,7 +371,7 @@ func (c *internalClient) ListExternalLocations(ctx context.Context, req *ListExt // // For example: // -// for item, err := range c.ListExternalLocationsIter(ctx, &ListExternalLocationsRequest{}) { +// for item, err := range c.ListExternalLocationsIter(ctx, ListExternalLocationsRequest{}) { // if err != nil { // return err // } @@ -375,16 +383,13 @@ func (c *internalClient) ListExternalLocations(ctx context.Context, req *ListExt // // Callers who need custom pagination logic should use // ListExternalLocations directly. -func (c *internalClient) ListExternalLocationsIter(ctx context.Context, req *ListExternalLocationsRequest, opts ...call.Option) iter.Seq2[*ExternalLocationInfo, error] { +func (c *internalClient) ListExternalLocationsIter(ctx context.Context, req ListExternalLocationsRequest, opts ...call.Option) iter.Seq2[*ExternalLocationInfo, error] { return func(yield func(*ExternalLocationInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListExternalLocationsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListExternalLocations(ctx, &pageReq, opts...) + resp, err := c.ListExternalLocations(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -405,8 +410,8 @@ func (c *internalClient) ListExternalLocationsIter(ctx context.Context, req *Lis // Updates an external location in the metastore. The caller must be the owner // of the external location, or be a metastore admin. In the second case, the // admin can only update the name of the external location. -func (c *internalClient) UpdateExternalLocation(ctx context.Context, req *UpdateExternalLocationRequest, opts ...call.Option) (*ExternalLocationInfo, error) { - wireReq, err := updateExternalLocationRequestToWire(req) +func (c *internalClient) UpdateExternalLocation(ctx context.Context, req UpdateExternalLocationRequest, opts ...call.Option) (*ExternalLocationInfo, error) { + wireReq, err := updateExternalLocationRequestToWire(&req) if err != nil { return nil, err } @@ -427,7 +432,11 @@ func (c *internalClient) UpdateExternalLocation(ctx context.Context, req *Update } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/external-locations/") - pb.singleSegment(*req.NameArg) + if req.NameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.NameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/uc/externallocations/v1/genhelper.go b/uc/externallocations/v1/genhelper.go old mode 100755 new mode 100644 index c3b1afb..c8caed9 --- a/uc/externallocations/v1/genhelper.go +++ b/uc/externallocations/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/externallocations/v1/wire.go b/uc/externallocations/v1/wire.go old mode 100755 new mode 100644 index 29b229d..b80a2c3 --- a/uc/externallocations/v1/wire.go +++ b/uc/externallocations/v1/wire.go @@ -3,9 +3,55 @@ package externallocations import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type awsSqsQueueWire struct { QueueUrl *string `json:"queue_url,omitempty"` ManagedResourceId *string `json:"managed_resource_id,omitempty"` @@ -75,9 +121,9 @@ type createExternalLocationRequestWire struct { EncryptionDetails *encryptionDetailsWire `json:"encryption_details,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` CredentialId *string `json:"credential_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` BrowseOnly *bool `json:"browse_only,omitempty"` IsolationMode IsolationMode `json:"isolation_mode,omitempty"` @@ -98,6 +144,14 @@ func createExternalLocationRequestToWire(v *CreateExternalLocationRequest) (*cre if err != nil { return nil, fmt.Errorf("%s: %w", "CreateExternalLocationRequest.EncryptionDetails", err) } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateExternalLocationRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateExternalLocationRequest.UpdatedAt", err) + } effectiveFileEventQueueWireValue, err := fileEventQueueToWire(v.EffectiveFileEventQueue) if err != nil { return nil, fmt.Errorf("%s: %w", "CreateExternalLocationRequest.EffectiveFileEventQueue", err) @@ -115,9 +169,9 @@ func createExternalLocationRequestToWire(v *CreateExternalLocationRequest) (*cre EncryptionDetails: encryptionDetailsWireValue, MetastoreId: v.MetastoreId, CredentialId: v.CredentialId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, BrowseOnly: v.BrowseOnly, IsolationMode: v.IsolationMode, @@ -206,9 +260,9 @@ type externalLocationInfoWire struct { EncryptionDetails *encryptionDetailsWire `json:"encryption_details,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` CredentialId *string `json:"credential_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` BrowseOnly *bool `json:"browse_only,omitempty"` IsolationMode IsolationMode `json:"isolation_mode,omitempty"` @@ -229,6 +283,14 @@ func externalLocationInfoFromWire(w *externalLocationInfoWire) (*ExternalLocatio if err != nil { return nil, fmt.Errorf("%s: %w", "ExternalLocationInfo.EncryptionDetails", err) } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ExternalLocationInfo.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ExternalLocationInfo.UpdatedAt", err) + } effectiveFileEventQueuePublicValue, err := fileEventQueueFromWire(w.EffectiveFileEventQueue) if err != nil { return nil, fmt.Errorf("%s: %w", "ExternalLocationInfo.EffectiveFileEventQueue", err) @@ -245,9 +307,9 @@ func externalLocationInfoFromWire(w *externalLocationInfoWire) (*ExternalLocatio EncryptionDetails: encryptionDetailsPublicValue, MetastoreId: w.MetastoreId, CredentialId: w.CredentialId, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, BrowseOnly: w.BrowseOnly, IsolationMode: w.IsolationMode, @@ -541,9 +603,9 @@ type updateExternalLocationRequestWire struct { EncryptionDetails *encryptionDetailsWire `json:"encryption_details,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` CredentialId *string `json:"credential_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` BrowseOnly *bool `json:"browse_only,omitempty"` IsolationMode IsolationMode `json:"isolation_mode,omitempty"` @@ -564,6 +626,14 @@ func updateExternalLocationRequestToWire(v *UpdateExternalLocationRequest) (*upd if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateExternalLocationRequest.EncryptionDetails", err) } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateExternalLocationRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateExternalLocationRequest.UpdatedAt", err) + } effectiveFileEventQueueWireValue, err := fileEventQueueToWire(v.EffectiveFileEventQueue) if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateExternalLocationRequest.EffectiveFileEventQueue", err) @@ -584,9 +654,9 @@ func updateExternalLocationRequestToWire(v *UpdateExternalLocationRequest) (*upd EncryptionDetails: encryptionDetailsWireValue, MetastoreId: v.MetastoreId, CredentialId: v.CredentialId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, BrowseOnly: v.BrowseOnly, IsolationMode: v.IsolationMode, diff --git a/uc/externalmetadata/CHANGELOG.md b/uc/externalmetadata/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/externalmetadata/CHANGELOG.md +++ b/uc/externalmetadata/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/externalmetadata/go.mod b/uc/externalmetadata/go.mod index a7fddd7..538004c 100644 --- a/uc/externalmetadata/go.mod +++ b/uc/externalmetadata/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/externalmetadata/internal/version.go b/uc/externalmetadata/internal/version.go index 6ee4919..bb5e114 100644 --- a/uc/externalmetadata/internal/version.go +++ b/uc/externalmetadata/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-externalmetadata" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/externalmetadata/v1/client.go b/uc/externalmetadata/v1/client.go old mode 100755 new mode 100644 index eae38b1..f2f5aa3 --- a/uc/externalmetadata/v1/client.go +++ b/uc/externalmetadata/v1/client.go @@ -77,8 +77,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Creates a new external metadata object in the parent metastore if the caller // is a metastore admin or has the **CREATE_EXTERNAL_METADATA** privilege. // Grants **BROWSE** to all account users upon creation by default. -func (c *internalClient) CreateExternalMetadataV2(ctx context.Context, req *CreateExternalMetadataRequest, opts ...call.Option) (*ExternalMetadata, error) { - wireReq, err := createExternalMetadataRequestToWire(req) +func (c *internalClient) CreateExternalMetadataV2(ctx context.Context, req CreateExternalMetadataRequest, opts ...call.Option) (*ExternalMetadata, error) { + wireReq, err := createExternalMetadataRequestToWire(&req) if err != nil { return nil, err } @@ -145,7 +145,7 @@ func (c *internalClient) CreateExternalMetadataV2(ctx context.Context, req *Crea // Deletes the external metadata object that matches the supplied name. The // caller must be a metastore admin, the owner of the external metadata object, // or a user that has the **MANAGE** privilege. -func (c *internalClient) DeleteExternalMetadataV2(ctx context.Context, req *DeleteExternalMetadataRequest, opts ...call.Option) error { +func (c *internalClient) DeleteExternalMetadataV2(ctx context.Context, req DeleteExternalMetadataRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -159,7 +159,11 @@ func (c *internalClient) DeleteExternalMetadataV2(ctx context.Context, req *Dele } pb := pathBuilder{} pb.literal("/api/2.0/lineage-tracking/external-metadata/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -198,7 +202,7 @@ func (c *internalClient) DeleteExternalMetadataV2(ctx context.Context, req *Dele // Gets the specified external metadata object in a metastore. The caller must // be a metastore admin, the owner of the external metadata object, or a user // that has the **BROWSE** privilege. -func (c *internalClient) GetExternalMetadataV2(ctx context.Context, req *GetExternalMetadataRequest, opts ...call.Option) (*ExternalMetadata, error) { +func (c *internalClient) GetExternalMetadataV2(ctx context.Context, req GetExternalMetadataRequest, opts ...call.Option) (*ExternalMetadata, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -212,7 +216,11 @@ func (c *internalClient) GetExternalMetadataV2(ctx context.Context, req *GetExte } pb := pathBuilder{} pb.literal("/api/2.0/lineage-tracking/external-metadata/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -262,8 +270,8 @@ func (c *internalClient) GetExternalMetadataV2(ctx context.Context, req *GetExte // Otherwise, only external metadata objects that the caller has **BROWSE** on // will be retrieved. There is no guarantee of a specific ordering of the // elements in the array. -func (c *internalClient) ListExternalMetadataV2(ctx context.Context, req *ListExternalMetadataRequest, opts ...call.Option) (*ListExternalMetadataResponseV2, error) { - wireReq, err := listExternalMetadataRequestToWire(req) +func (c *internalClient) ListExternalMetadataV2(ctx context.Context, req ListExternalMetadataRequest, opts ...call.Option) (*ListExternalMetadataResponseV2, error) { + wireReq, err := listExternalMetadataRequestToWire(&req) if err != nil { return nil, err } @@ -333,7 +341,7 @@ func (c *internalClient) ListExternalMetadataV2(ctx context.Context, req *ListEx // // For example: // -// for item, err := range c.ListExternalMetadataV2Iter(ctx, &ListExternalMetadataRequest{}) { +// for item, err := range c.ListExternalMetadataV2Iter(ctx, ListExternalMetadataRequest{}) { // if err != nil { // return err // } @@ -345,16 +353,13 @@ func (c *internalClient) ListExternalMetadataV2(ctx context.Context, req *ListEx // // Callers who need custom pagination logic should use // ListExternalMetadataV2 directly. -func (c *internalClient) ListExternalMetadataV2Iter(ctx context.Context, req *ListExternalMetadataRequest, opts ...call.Option) iter.Seq2[*ExternalMetadata, error] { +func (c *internalClient) ListExternalMetadataV2Iter(ctx context.Context, req ListExternalMetadataRequest, opts ...call.Option) iter.Seq2[*ExternalMetadata, error] { return func(yield func(*ExternalMetadata, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListExternalMetadataRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListExternalMetadataV2(ctx, &pageReq, opts...) + resp, err := c.ListExternalMetadataV2(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -377,8 +382,8 @@ func (c *internalClient) ListExternalMetadataV2Iter(ctx context.Context, req *Li // request. The caller must be a metastore admin, the owner of the external // metadata object, or a user that has the **MODIFY** privilege. If the caller // is updating the owner, they must also have the **MANAGE** privilege. -func (c *internalClient) UpdateExternalMetadataV2(ctx context.Context, req *UpdateExternalMetadataRequest, opts ...call.Option) (*ExternalMetadata, error) { - wireReq, err := updateExternalMetadataRequestToWire(req) +func (c *internalClient) UpdateExternalMetadataV2(ctx context.Context, req UpdateExternalMetadataRequest, opts ...call.Option) (*ExternalMetadata, error) { + wireReq, err := updateExternalMetadataRequestToWire(&req) if err != nil { return nil, err } @@ -399,7 +404,11 @@ func (c *internalClient) UpdateExternalMetadataV2(ctx context.Context, req *Upda } pb := pathBuilder{} pb.literal("/api/2.0/lineage-tracking/external-metadata/") - pb.singleSegment(*req.ExternalMetadata.Name) + if req.ExternalMetadata == nil || req.ExternalMetadata.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ExternalMetadata.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { diff --git a/uc/externalmetadata/v1/genhelper.go b/uc/externalmetadata/v1/genhelper.go old mode 100755 new mode 100644 index 70cfe89..b4a0e1a --- a/uc/externalmetadata/v1/genhelper.go +++ b/uc/externalmetadata/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/functions/CHANGELOG.md b/uc/functions/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/functions/CHANGELOG.md +++ b/uc/functions/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/functions/go.mod b/uc/functions/go.mod index d6e68d8..6e96b57 100644 --- a/uc/functions/go.mod +++ b/uc/functions/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/functions/internal/version.go b/uc/functions/internal/version.go index 64bf9f4..2a7dde8 100644 --- a/uc/functions/internal/version.go +++ b/uc/functions/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-functions" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/functions/v1/client.go b/uc/functions/v1/client.go old mode 100755 new mode 100644 index 2d39620..61467ab --- a/uc/functions/v1/client.go +++ b/uc/functions/v1/client.go @@ -81,8 +81,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // The user must have the following permissions in order for the function to be // created: - **USE_CATALOG** on the function's parent catalog - **USE_SCHEMA** // and **CREATE_FUNCTION** on the function's parent schema -func (c *internalClient) CreateFunction(ctx context.Context, req *CreateFunctionRequest, opts ...call.Option) (*FunctionInfo, error) { - wireReq, err := createFunctionRequestToWire(req) +func (c *internalClient) CreateFunction(ctx context.Context, req CreateFunctionRequest, opts ...call.Option) (*FunctionInfo, error) { + wireReq, err := createFunctionRequestToWire(&req) if err != nil { return nil, err } @@ -153,8 +153,8 @@ func (c *internalClient) CreateFunction(ctx context.Context, req *CreateFunction // Is the owner of the function itself and have both the **USE_CATALOG** // privilege on its parent catalog and the **USE_SCHEMA** privilege on its // parent schema -func (c *internalClient) DeleteFunction(ctx context.Context, req *DeleteFunctionRequest, opts ...call.Option) (*DeleteFunctionResponse, error) { - wireReq, err := deleteFunctionRequestToWire(req) +func (c *internalClient) DeleteFunction(ctx context.Context, req DeleteFunctionRequest, opts ...call.Option) (*DeleteFunctionResponse, error) { + wireReq, err := deleteFunctionRequestToWire(&req) if err != nil { return nil, err } @@ -171,7 +171,11 @@ func (c *internalClient) DeleteFunction(ctx context.Context, req *DeleteFunction } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/functions/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "force", wireReq.Force); err != nil { @@ -220,8 +224,8 @@ func (c *internalClient) DeleteFunction(ctx context.Context, req *DeleteFunction // of the function - Have the **USE_CATALOG** privilege on the function's parent // catalog, the **USE_SCHEMA** privilege on the function's parent schema, and // the **EXECUTE** privilege on the function itself -func (c *internalClient) GetFunction(ctx context.Context, req *GetFunctionRequest, opts ...call.Option) (*FunctionInfo, error) { - wireReq, err := getFunctionRequestToWire(req) +func (c *internalClient) GetFunction(ctx context.Context, req GetFunctionRequest, opts ...call.Option) (*FunctionInfo, error) { + wireReq, err := getFunctionRequestToWire(&req) if err != nil { return nil, err } @@ -238,7 +242,11 @@ func (c *internalClient) GetFunction(ctx context.Context, req *GetFunctionReques } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/functions/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "include_browse", wireReq.IncludeBrowse); err != nil { @@ -301,8 +309,8 @@ func (c *internalClient) GetFunction(ctx context.Context, req *GetFunctionReques // contain zero results while still providing a next_page_token. Clients must // continue reading pages until next_page_token is absent, which is the only // indication that the end of results has been reached. -func (c *internalClient) ListFunctions(ctx context.Context, req *ListFunctionsRequest, opts ...call.Option) (*ListFunctionsResponse, error) { - wireReq, err := listFunctionsRequestToWire(req) +func (c *internalClient) ListFunctions(ctx context.Context, req ListFunctionsRequest, opts ...call.Option) (*ListFunctionsResponse, error) { + wireReq, err := listFunctionsRequestToWire(&req) if err != nil { return nil, err } @@ -381,7 +389,7 @@ func (c *internalClient) ListFunctions(ctx context.Context, req *ListFunctionsRe // // For example: // -// for item, err := range c.ListFunctionsIter(ctx, &ListFunctionsRequest{}) { +// for item, err := range c.ListFunctionsIter(ctx, ListFunctionsRequest{}) { // if err != nil { // return err // } @@ -393,16 +401,13 @@ func (c *internalClient) ListFunctions(ctx context.Context, req *ListFunctionsRe // // Callers who need custom pagination logic should use // ListFunctions directly. -func (c *internalClient) ListFunctionsIter(ctx context.Context, req *ListFunctionsRequest, opts ...call.Option) iter.Seq2[*FunctionInfo, error] { +func (c *internalClient) ListFunctionsIter(ctx context.Context, req ListFunctionsRequest, opts ...call.Option) iter.Seq2[*FunctionInfo, error] { return func(yield func(*FunctionInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListFunctionsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListFunctions(ctx, &pageReq, opts...) + resp, err := c.ListFunctions(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -428,8 +433,8 @@ func (c *internalClient) ListFunctionsIter(ctx context.Context, req *ListFunctio // catalog - Is the owner of the function itself and has the **USE_CATALOG** // privilege on its parent catalog as well as the **USE_SCHEMA** privilege on // the function's parent schema. -func (c *internalClient) UpdateFunction(ctx context.Context, req *UpdateFunctionRequest, opts ...call.Option) (*FunctionInfo, error) { - wireReq, err := updateFunctionRequestToWire(req) +func (c *internalClient) UpdateFunction(ctx context.Context, req UpdateFunctionRequest, opts ...call.Option) (*FunctionInfo, error) { + wireReq, err := updateFunctionRequestToWire(&req) if err != nil { return nil, err } @@ -450,7 +455,11 @@ func (c *internalClient) UpdateFunction(ctx context.Context, req *UpdateFunction } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/functions/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/uc/functions/v1/genhelper.go b/uc/functions/v1/genhelper.go old mode 100755 new mode 100644 index e15811e..5fe32a6 --- a/uc/functions/v1/genhelper.go +++ b/uc/functions/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/functions/v1/model.go b/uc/functions/v1/model.go old mode 100755 new mode 100644 index e541e27..8cd41cf --- a/uc/functions/v1/model.go +++ b/uc/functions/v1/model.go @@ -134,7 +134,8 @@ type CreateFunction struct { Comment *string // JSON-serialized key-value pair map, encoded (escaped) as a string. Properties *string - // function dependencies. + // Function dependencies. For external UDFs, dependencies may contain only + // credential, secret, or volume objects. RoutineDependencies *DependencyList // Unique identifier of parent metastore. MetastoreId *string @@ -277,7 +278,8 @@ type FunctionInfo struct { Comment *string // JSON-serialized key-value pair map, encoded (escaped) as a string. Properties *string - // function dependencies. + // Function dependencies. For external UDFs, dependencies may contain only + // credential, secret, or volume objects. RoutineDependencies *DependencyList // Unique identifier of parent metastore. MetastoreId *string @@ -423,7 +425,8 @@ type UpdateFunctionRequest struct { Comment *string // JSON-serialized key-value pair map, encoded (escaped) as a string. Properties *string - // function dependencies. + // Function dependencies. For external UDFs, dependencies may contain only + // credential, secret, or volume objects. RoutineDependencies *DependencyList // Unique identifier of parent metastore. MetastoreId *string diff --git a/uc/functions/v1/wire.go b/uc/functions/v1/wire.go old mode 100755 new mode 100644 index b6afbde..e744add --- a/uc/functions/v1/wire.go +++ b/uc/functions/v1/wire.go @@ -3,9 +3,55 @@ package functions import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type connectionDependencyWire struct { ConnectionName *string `json:"connection_name,omitempty"` } @@ -53,9 +99,9 @@ type createFunctionWire struct { RoutineDependencies *dependencyListWire `json:"routine_dependencies,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` FullName *string `json:"full_name,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` FunctionId *string `json:"function_id,omitempty"` BrowseOnly *bool `json:"browse_only,omitempty"` @@ -77,6 +123,14 @@ func createFunctionToWire(v *CreateFunction) (*createFunctionWire, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "CreateFunction.RoutineDependencies", err) } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateFunction.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateFunction.UpdatedAt", err) + } return &createFunctionWire{ Name: v.Name, CatalogName: v.CatalogName, @@ -102,9 +156,9 @@ func createFunctionToWire(v *CreateFunction) (*createFunctionWire, error) { RoutineDependencies: routineDependenciesWireValue, MetastoreId: v.MetastoreId, FullName: v.FullName, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, FunctionId: v.FunctionId, BrowseOnly: v.BrowseOnly, @@ -354,9 +408,9 @@ type functionInfoWire struct { RoutineDependencies *dependencyListWire `json:"routine_dependencies,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` FullName *string `json:"full_name,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` FunctionId *string `json:"function_id,omitempty"` BrowseOnly *bool `json:"browse_only,omitempty"` @@ -378,6 +432,14 @@ func functionInfoFromWire(w *functionInfoWire) (*FunctionInfo, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "FunctionInfo.RoutineDependencies", err) } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FunctionInfo.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FunctionInfo.UpdatedAt", err) + } return &FunctionInfo{ Name: w.Name, CatalogName: w.CatalogName, @@ -403,9 +465,9 @@ func functionInfoFromWire(w *functionInfoWire) (*FunctionInfo, error) { RoutineDependencies: routineDependenciesPublicValue, MetastoreId: w.MetastoreId, FullName: w.FullName, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, FunctionId: w.FunctionId, BrowseOnly: w.BrowseOnly, @@ -600,9 +662,9 @@ type updateFunctionRequestWire struct { RoutineDependencies *dependencyListWire `json:"routine_dependencies,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` FullName *string `json:"full_name,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` FunctionId *string `json:"function_id,omitempty"` BrowseOnly *bool `json:"browse_only,omitempty"` @@ -624,6 +686,14 @@ func updateFunctionRequestToWire(v *UpdateFunctionRequest) (*updateFunctionReque if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateFunctionRequest.RoutineDependencies", err) } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateFunctionRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateFunctionRequest.UpdatedAt", err) + } return &updateFunctionRequestWire{ FullNameArg: v.FullNameArg, Name: v.Name, @@ -650,9 +720,9 @@ func updateFunctionRequestToWire(v *UpdateFunctionRequest) (*updateFunctionReque RoutineDependencies: routineDependenciesWireValue, MetastoreId: v.MetastoreId, FullName: v.FullName, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, FunctionId: v.FunctionId, BrowseOnly: v.BrowseOnly, diff --git a/uc/grants/CHANGELOG.md b/uc/grants/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/grants/CHANGELOG.md +++ b/uc/grants/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/grants/go.mod b/uc/grants/go.mod index 04066e2..e8c9a40 100644 --- a/uc/grants/go.mod +++ b/uc/grants/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/grants/internal/version.go b/uc/grants/internal/version.go index 99b7ca3..818d1cf 100644 --- a/uc/grants/internal/version.go +++ b/uc/grants/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-grants" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/grants/v1/client.go b/uc/grants/v1/client.go old mode 100755 new mode 100644 index 3b11cfa..5069db8 --- a/uc/grants/v1/client.go +++ b/uc/grants/v1/client.go @@ -84,8 +84,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // contain zero results while still providing a next_page_token. Clients must // continue reading pages until next_page_token is absent, which is the only // indication that the end of results has been reached. -func (c *internalClient) GetEffectivePermissions(ctx context.Context, req *GetEffectivePermissionsRequest, opts ...call.Option) (*GetEffectivePermissionsResponse, error) { - wireReq, err := getEffectivePermissionsRequestToWire(req) +func (c *internalClient) GetEffectivePermissions(ctx context.Context, req GetEffectivePermissionsRequest, opts ...call.Option) (*GetEffectivePermissionsResponse, error) { + wireReq, err := getEffectivePermissionsRequestToWire(&req) if err != nil { return nil, err } @@ -102,9 +102,17 @@ func (c *internalClient) GetEffectivePermissions(ctx context.Context, req *GetEf } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/effective-permissions/") - pb.singleSegment(*req.SecurableType) + if req.SecurableType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SecurableType) + } pb.literal("/") - pb.singleSegment(*req.SecurableFullName) + if req.SecurableFullName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SecurableFullName) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "principal", wireReq.Principal); err != nil { @@ -167,8 +175,8 @@ func (c *internalClient) GetEffectivePermissions(ctx context.Context, req *GetEf // contain zero results while still providing a next_page_token. Clients must // continue reading pages until next_page_token is absent, which is the only // indication that the end of results has been reached. -func (c *internalClient) GetPermissions(ctx context.Context, req *GetPermissionsRequest, opts ...call.Option) (*GetPermissionsResponse, error) { - wireReq, err := getPermissionsRequestToWire(req) +func (c *internalClient) GetPermissions(ctx context.Context, req GetPermissionsRequest, opts ...call.Option) (*GetPermissionsResponse, error) { + wireReq, err := getPermissionsRequestToWire(&req) if err != nil { return nil, err } @@ -185,9 +193,17 @@ func (c *internalClient) GetPermissions(ctx context.Context, req *GetPermissions } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/permissions/") - pb.singleSegment(*req.SecurableType) + if req.SecurableType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SecurableType) + } pb.literal("/") - pb.singleSegment(*req.SecurableFullName) + if req.SecurableFullName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SecurableFullName) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "principal", wireReq.Principal); err != nil { @@ -243,8 +259,8 @@ func (c *internalClient) GetPermissions(ctx context.Context, req *GetPermissions // Lists the effective privilege assignments for a securable. Includes inherited // privileges. Paginated version of Get Effective Permissions API. -func (c *internalClient) ListEffectivePrivilegeAssignments(ctx context.Context, req *ListEffectivePrivilegeAssignmentsRequest, opts ...call.Option) (*ListEffectivePrivilegeAssignmentsResponse, error) { - wireReq, err := listEffectivePrivilegeAssignmentsRequestToWire(req) +func (c *internalClient) ListEffectivePrivilegeAssignments(ctx context.Context, req ListEffectivePrivilegeAssignmentsRequest, opts ...call.Option) (*ListEffectivePrivilegeAssignmentsResponse, error) { + wireReq, err := listEffectivePrivilegeAssignmentsRequestToWire(&req) if err != nil { return nil, err } @@ -261,9 +277,17 @@ func (c *internalClient) ListEffectivePrivilegeAssignments(ctx context.Context, } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/effective-privilege-assignments/") - pb.singleSegment(*req.SecurableType) + if req.SecurableType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SecurableType) + } pb.literal("/") - pb.singleSegment(*req.FullName) + if req.FullName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullName) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "principal", wireReq.Principal); err != nil { @@ -322,7 +346,7 @@ func (c *internalClient) ListEffectivePrivilegeAssignments(ctx context.Context, // // For example: // -// for item, err := range c.ListEffectivePrivilegeAssignmentsIter(ctx, &ListEffectivePrivilegeAssignmentsRequest{}) { +// for item, err := range c.ListEffectivePrivilegeAssignmentsIter(ctx, ListEffectivePrivilegeAssignmentsRequest{}) { // if err != nil { // return err // } @@ -334,16 +358,13 @@ func (c *internalClient) ListEffectivePrivilegeAssignments(ctx context.Context, // // Callers who need custom pagination logic should use // ListEffectivePrivilegeAssignments directly. -func (c *internalClient) ListEffectivePrivilegeAssignmentsIter(ctx context.Context, req *ListEffectivePrivilegeAssignmentsRequest, opts ...call.Option) iter.Seq2[*EffectivePrivilegeAssignment, error] { +func (c *internalClient) ListEffectivePrivilegeAssignmentsIter(ctx context.Context, req ListEffectivePrivilegeAssignmentsRequest, opts ...call.Option) iter.Seq2[*EffectivePrivilegeAssignment, error] { return func(yield func(*EffectivePrivilegeAssignment, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListEffectivePrivilegeAssignmentsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListEffectivePrivilegeAssignments(ctx, &pageReq, opts...) + resp, err := c.ListEffectivePrivilegeAssignments(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -363,8 +384,8 @@ func (c *internalClient) ListEffectivePrivilegeAssignmentsIter(ctx context.Conte // Lists the privilege assignments for a securable. Does not include inherited // privileges. Paginated version of Get Permissions API. -func (c *internalClient) ListPrivilegeAssignments(ctx context.Context, req *ListPrivilegeAssignmentsRequest, opts ...call.Option) (*ListPrivilegeAssignmentsResponse, error) { - wireReq, err := listPrivilegeAssignmentsRequestToWire(req) +func (c *internalClient) ListPrivilegeAssignments(ctx context.Context, req ListPrivilegeAssignmentsRequest, opts ...call.Option) (*ListPrivilegeAssignmentsResponse, error) { + wireReq, err := listPrivilegeAssignmentsRequestToWire(&req) if err != nil { return nil, err } @@ -381,9 +402,17 @@ func (c *internalClient) ListPrivilegeAssignments(ctx context.Context, req *List } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/privilege-assignments/") - pb.singleSegment(*req.SecurableType) + if req.SecurableType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SecurableType) + } pb.literal("/") - pb.singleSegment(*req.FullName) + if req.FullName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullName) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "principal", wireReq.Principal); err != nil { @@ -442,7 +471,7 @@ func (c *internalClient) ListPrivilegeAssignments(ctx context.Context, req *List // // For example: // -// for item, err := range c.ListPrivilegeAssignmentsIter(ctx, &ListPrivilegeAssignmentsRequest{}) { +// for item, err := range c.ListPrivilegeAssignmentsIter(ctx, ListPrivilegeAssignmentsRequest{}) { // if err != nil { // return err // } @@ -454,16 +483,13 @@ func (c *internalClient) ListPrivilegeAssignments(ctx context.Context, req *List // // Callers who need custom pagination logic should use // ListPrivilegeAssignments directly. -func (c *internalClient) ListPrivilegeAssignmentsIter(ctx context.Context, req *ListPrivilegeAssignmentsRequest, opts ...call.Option) iter.Seq2[*PrivilegeAssignment, error] { +func (c *internalClient) ListPrivilegeAssignmentsIter(ctx context.Context, req ListPrivilegeAssignmentsRequest, opts ...call.Option) iter.Seq2[*PrivilegeAssignment, error] { return func(yield func(*PrivilegeAssignment, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListPrivilegeAssignmentsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListPrivilegeAssignments(ctx, &pageReq, opts...) + resp, err := c.ListPrivilegeAssignments(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -482,8 +508,8 @@ func (c *internalClient) ListPrivilegeAssignmentsIter(ctx context.Context, req * } // Updates the permissions for a securable. -func (c *internalClient) UpdatePermissions(ctx context.Context, req *UpdatePermissionsRequest, opts ...call.Option) (*UpdatePermissionsResponse, error) { - wireReq, err := updatePermissionsRequestToWire(req) +func (c *internalClient) UpdatePermissions(ctx context.Context, req UpdatePermissionsRequest, opts ...call.Option) (*UpdatePermissionsResponse, error) { + wireReq, err := updatePermissionsRequestToWire(&req) if err != nil { return nil, err } @@ -504,9 +530,17 @@ func (c *internalClient) UpdatePermissions(ctx context.Context, req *UpdatePermi } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/permissions/") - pb.singleSegment(*req.SecurableType) + if req.SecurableType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SecurableType) + } pb.literal("/") - pb.singleSegment(*req.SecurableFullName) + if req.SecurableFullName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SecurableFullName) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/uc/grants/v1/genhelper.go b/uc/grants/v1/genhelper.go old mode 100755 new mode 100644 index 9384e9d..fc1c0e0 --- a/uc/grants/v1/genhelper.go +++ b/uc/grants/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/metastores/CHANGELOG.md b/uc/metastores/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/metastores/CHANGELOG.md +++ b/uc/metastores/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/metastores/go.mod b/uc/metastores/go.mod index c81ab1b..8967de1 100644 --- a/uc/metastores/go.mod +++ b/uc/metastores/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/metastores/internal/version.go b/uc/metastores/internal/version.go index 6a76018..c49e9bf 100644 --- a/uc/metastores/internal/version.go +++ b/uc/metastores/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-metastores" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/metastores/v1/client.go b/uc/metastores/v1/client.go old mode 100755 new mode 100644 index ae93a6f..7e52f86 --- a/uc/metastores/v1/client.go +++ b/uc/metastores/v1/client.go @@ -76,8 +76,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Creates a Unity Catalog metastore. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateAccountsMetastore(ctx context.Context, req *AccountsCreateMetastoreRequest, opts ...call.Option) (*AccountsCreateMetastoreResponse, error) { - wireReq, err := accountsCreateMetastoreRequestToWire(req) +func (c *internalClient) CreateAccountsMetastore(ctx context.Context, req AccountsCreateMetastoreRequest, opts ...call.Option) (*AccountsCreateMetastoreResponse, error) { + wireReq, err := accountsCreateMetastoreRequestToWire(&req) if err != nil { return nil, err } @@ -148,8 +148,8 @@ func (c *internalClient) CreateAccountsMetastore(ctx context.Context, req *Accou // Creates an assignment to a metastore for a workspace // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateAccountsMetastoreAssignment(ctx context.Context, req *AccountsCreateMetastoreAssignmentRequest, opts ...call.Option) (*AccountsCreateMetastoreAssignmentResponse, error) { - wireReq, err := accountsCreateMetastoreAssignmentRequestToWire(req) +func (c *internalClient) CreateAccountsMetastoreAssignment(ctx context.Context, req AccountsCreateMetastoreAssignmentRequest, opts ...call.Option) (*AccountsCreateMetastoreAssignmentResponse, error) { + wireReq, err := accountsCreateMetastoreAssignmentRequestToWire(&req) if err != nil { return nil, err } @@ -173,9 +173,17 @@ func (c *internalClient) CreateAccountsMetastoreAssignment(ctx context.Context, pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/workspaces/") - pb.singleSegment(*req.WorkspaceId) + if req.WorkspaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.WorkspaceId) + } pb.literal("/metastores/") - pb.singleSegment(*req.MetastoreId) + if req.MetastoreId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MetastoreId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -217,8 +225,8 @@ func (c *internalClient) CreateAccountsMetastoreAssignment(ctx context.Context, // Deletes a Unity Catalog metastore for an account, both specified by ID. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteAccountsMetastore(ctx context.Context, req *AccountsDeleteMetastoreRequest, opts ...call.Option) (*AccountsDeleteMetastoreResponse, error) { - wireReq, err := accountsDeleteMetastoreRequestToWire(req) +func (c *internalClient) DeleteAccountsMetastore(ctx context.Context, req AccountsDeleteMetastoreRequest, opts ...call.Option) (*AccountsDeleteMetastoreResponse, error) { + wireReq, err := accountsDeleteMetastoreRequestToWire(&req) if err != nil { return nil, err } @@ -238,7 +246,11 @@ func (c *internalClient) DeleteAccountsMetastore(ctx context.Context, req *Accou pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/metastores/") - pb.singleSegment(*req.MetastoreId) + if req.MetastoreId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MetastoreId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "force", wireReq.Force); err != nil { @@ -283,7 +295,7 @@ func (c *internalClient) DeleteAccountsMetastore(ctx context.Context, req *Accou // Deletes a metastore assignment to a workspace, leaving the workspace with no // metastore. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteAccountsMetastoreAssignment(ctx context.Context, req *AccountsDeleteMetastoreAssignmentRequest, opts ...call.Option) (*AccountsDeleteMetastoreAssignmentResponse, error) { +func (c *internalClient) DeleteAccountsMetastoreAssignment(ctx context.Context, req AccountsDeleteMetastoreAssignmentRequest, opts ...call.Option) (*AccountsDeleteMetastoreAssignmentResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -300,9 +312,17 @@ func (c *internalClient) DeleteAccountsMetastoreAssignment(ctx context.Context, pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/workspaces/") - pb.singleSegment(*req.WorkspaceId) + if req.WorkspaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.WorkspaceId) + } pb.literal("/metastores/") - pb.singleSegment(*req.MetastoreId) + if req.MetastoreId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MetastoreId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -343,7 +363,7 @@ func (c *internalClient) DeleteAccountsMetastoreAssignment(ctx context.Context, // Gets a Unity Catalog metastore from an account, both specified by ID. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetAccountsMetastore(ctx context.Context, req *AccountsGetMetastoreRequest, opts ...call.Option) (*AccountsGetMetastoreResponse, error) { +func (c *internalClient) GetAccountsMetastore(ctx context.Context, req AccountsGetMetastoreRequest, opts ...call.Option) (*AccountsGetMetastoreResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -360,7 +380,11 @@ func (c *internalClient) GetAccountsMetastore(ctx context.Context, req *Accounts pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/metastores/") - pb.singleSegment(*req.MetastoreId) + if req.MetastoreId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MetastoreId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -410,7 +434,7 @@ func (c *internalClient) GetAccountsMetastore(ctx context.Context, req *Accounts // metastore is assigned to the workspace, the assignment will not be found and // a 404 returned. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetMetastoreAssignment(ctx context.Context, req *AccountsGetMetastoreAssignmentRequest, opts ...call.Option) (*AccountsGetMetastoreAssignmentResponse, error) { +func (c *internalClient) GetMetastoreAssignment(ctx context.Context, req AccountsGetMetastoreAssignmentRequest, opts ...call.Option) (*AccountsGetMetastoreAssignmentResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -427,7 +451,11 @@ func (c *internalClient) GetMetastoreAssignment(ctx context.Context, req *Accoun pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/workspaces/") - pb.singleSegment(*req.WorkspaceId) + if req.WorkspaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.WorkspaceId) + } pb.literal("/metastore") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -475,7 +503,7 @@ func (c *internalClient) GetMetastoreAssignment(ctx context.Context, req *Accoun // Gets all Unity Catalog metastores associated with an account specified by ID. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListAccountsMetastores(ctx context.Context, req *AccountsListMetastoresRequest, opts ...call.Option) (*AccountsListMetastoresResponse, error) { +func (c *internalClient) ListAccountsMetastores(ctx context.Context, req AccountsListMetastoresRequest, opts ...call.Option) (*AccountsListMetastoresResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -539,7 +567,7 @@ func (c *internalClient) ListAccountsMetastores(ctx context.Context, req *Accoun // Gets a list of all workspace IDs that have been assigned to // given metastore. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListMetastoreAssignments(ctx context.Context, req *AccountsListWorkspaceIdsForMetastoreRequest, opts ...call.Option) (*AccountsListWorkspaceIdsForMetastoreResponse, error) { +func (c *internalClient) ListMetastoreAssignments(ctx context.Context, req AccountsListWorkspaceIdsForMetastoreRequest, opts ...call.Option) (*AccountsListWorkspaceIdsForMetastoreResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -556,7 +584,11 @@ func (c *internalClient) ListMetastoreAssignments(ctx context.Context, req *Acco pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/metastores/") - pb.singleSegment(*req.MetastoreId) + if req.MetastoreId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MetastoreId) + } pb.literal("/workspaces") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -604,8 +636,8 @@ func (c *internalClient) ListMetastoreAssignments(ctx context.Context, req *Acco // Updates an existing Unity Catalog metastore. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdateAccountsMetastore(ctx context.Context, req *AccountsUpdateMetastoreRequest, opts ...call.Option) (*AccountsUpdateMetastoreResponse, error) { - wireReq, err := accountsUpdateMetastoreRequestToWire(req) +func (c *internalClient) UpdateAccountsMetastore(ctx context.Context, req AccountsUpdateMetastoreRequest, opts ...call.Option) (*AccountsUpdateMetastoreResponse, error) { + wireReq, err := accountsUpdateMetastoreRequestToWire(&req) if err != nil { return nil, err } @@ -629,7 +661,11 @@ func (c *internalClient) UpdateAccountsMetastore(ctx context.Context, req *Accou pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/metastores/") - pb.singleSegment(*req.MetastoreId) + if req.MetastoreId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MetastoreId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -678,8 +714,8 @@ func (c *internalClient) UpdateAccountsMetastore(ctx context.Context, req *Accou // Updates an assignment to a metastore for a workspace. Currently, only the // default catalog may be updated. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) UpdateAccountsMetastoreAssignment(ctx context.Context, req *AccountsUpdateMetastoreAssignmentRequest, opts ...call.Option) (*AccountsUpdateMetastoreAssignmentResponse, error) { - wireReq, err := accountsUpdateMetastoreAssignmentRequestToWire(req) +func (c *internalClient) UpdateAccountsMetastoreAssignment(ctx context.Context, req AccountsUpdateMetastoreAssignmentRequest, opts ...call.Option) (*AccountsUpdateMetastoreAssignmentResponse, error) { + wireReq, err := accountsUpdateMetastoreAssignmentRequestToWire(&req) if err != nil { return nil, err } @@ -703,9 +739,17 @@ func (c *internalClient) UpdateAccountsMetastoreAssignment(ctx context.Context, pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/workspaces/") - pb.singleSegment(*req.WorkspaceId) + if req.WorkspaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.WorkspaceId) + } pb.literal("/metastores/") - pb.singleSegment(*req.MetastoreId) + if req.MetastoreId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MetastoreId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -750,8 +794,8 @@ func (c *internalClient) UpdateAccountsMetastoreAssignment(ctx context.Context, // metastore is the user calling the __createMetastore__ API. If the __owner__ // field is set to the empty string (**""**), the ownership is assigned to the // System User instead. -func (c *internalClient) CreateMetastore(ctx context.Context, req *CreateMetastoreRequest, opts ...call.Option) (*MetastoreInfo, error) { - wireReq, err := createMetastoreRequestToWire(req) +func (c *internalClient) CreateMetastore(ctx context.Context, req CreateMetastoreRequest, opts ...call.Option) (*MetastoreInfo, error) { + wireReq, err := createMetastoreRequestToWire(&req) if err != nil { return nil, err } @@ -818,8 +862,8 @@ func (c *internalClient) CreateMetastore(ctx context.Context, req *CreateMetasto // Creates a new metastore assignment. If an assignment for the same // __workspace_id__ exists, it will be overwritten by the new __metastore_id__ // and __default_catalog_name__. The caller must be an account admin. -func (c *internalClient) CreateMetastoreAssignment(ctx context.Context, req *CreateMetastoreAssignmentRequest, opts ...call.Option) (*CreateMetastoreAssignmentResponse, error) { - wireReq, err := createMetastoreAssignmentRequestToWire(req) +func (c *internalClient) CreateMetastoreAssignment(ctx context.Context, req CreateMetastoreAssignmentRequest, opts ...call.Option) (*CreateMetastoreAssignmentResponse, error) { + wireReq, err := createMetastoreAssignmentRequestToWire(&req) if err != nil { return nil, err } @@ -840,7 +884,11 @@ func (c *internalClient) CreateMetastoreAssignment(ctx context.Context, req *Cre } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/workspaces/") - pb.singleSegment(*req.WorkspaceId) + if req.WorkspaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.WorkspaceId) + } pb.literal("/metastore") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -882,8 +930,8 @@ func (c *internalClient) CreateMetastoreAssignment(ctx context.Context, req *Cre } // Deletes a metastore. The caller must be a metastore admin. -func (c *internalClient) DeleteMetastore(ctx context.Context, req *DeleteMetastoreRequest, opts ...call.Option) (*DeleteMetastoreResponse, error) { - wireReq, err := deleteMetastoreRequestToWire(req) +func (c *internalClient) DeleteMetastore(ctx context.Context, req DeleteMetastoreRequest, opts ...call.Option) (*DeleteMetastoreResponse, error) { + wireReq, err := deleteMetastoreRequestToWire(&req) if err != nil { return nil, err } @@ -900,7 +948,11 @@ func (c *internalClient) DeleteMetastore(ctx context.Context, req *DeleteMetasto } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/metastores/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "force", wireReq.Force); err != nil { @@ -943,8 +995,8 @@ func (c *internalClient) DeleteMetastore(ctx context.Context, req *DeleteMetasto } // Deletes a metastore assignment. The caller must be an account administrator. -func (c *internalClient) DeleteMetastoreAssignment(ctx context.Context, req *DeleteMetastoreAssignmentRequest, opts ...call.Option) (*DeleteMetastoreAssignmentResponse, error) { - wireReq, err := deleteMetastoreAssignmentRequestToWire(req) +func (c *internalClient) DeleteMetastoreAssignment(ctx context.Context, req DeleteMetastoreAssignmentRequest, opts ...call.Option) (*DeleteMetastoreAssignmentResponse, error) { + wireReq, err := deleteMetastoreAssignmentRequestToWire(&req) if err != nil { return nil, err } @@ -961,7 +1013,11 @@ func (c *internalClient) DeleteMetastoreAssignment(ctx context.Context, req *Del } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/workspaces/") - pb.singleSegment(*req.WorkspaceId) + if req.WorkspaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.WorkspaceId) + } pb.literal("/metastore") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1005,7 +1061,7 @@ func (c *internalClient) DeleteMetastoreAssignment(ctx context.Context, req *Del } // Gets the metastore assignment for the workspace being accessed. -func (c *internalClient) GetCurrentMetastoreAssignment(ctx context.Context, req *GetCurrentMetastoreAssignmentRequest, opts ...call.Option) (*MetastoreAssignment, error) { +func (c *internalClient) GetCurrentMetastoreAssignment(ctx context.Context, req GetCurrentMetastoreAssignmentRequest, opts ...call.Option) (*MetastoreAssignment, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1063,7 +1119,7 @@ func (c *internalClient) GetCurrentMetastoreAssignment(ctx context.Context, req // Gets a metastore that matches the supplied ID. The caller must be a metastore // admin to retrieve this info. -func (c *internalClient) GetMetastore(ctx context.Context, req *GetMetastoreRequest, opts ...call.Option) (*MetastoreInfo, error) { +func (c *internalClient) GetMetastore(ctx context.Context, req GetMetastoreRequest, opts ...call.Option) (*MetastoreInfo, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1077,7 +1133,11 @@ func (c *internalClient) GetMetastore(ctx context.Context, req *GetMetastoreRequ } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/metastores/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1124,7 +1184,7 @@ func (c *internalClient) GetMetastore(ctx context.Context, req *GetMetastoreRequ // Gets information about a metastore. This summary includes the storage // credential, the cloud vendor, the cloud region, and the global metastore ID. -func (c *internalClient) GetMetastoreSummary(ctx context.Context, req *GetMetastoreSummaryRequest, opts ...call.Option) (*GetMetastoreSummaryResponse, error) { +func (c *internalClient) GetMetastoreSummary(ctx context.Context, req GetMetastoreSummaryRequest, opts ...call.Option) (*GetMetastoreSummaryResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -1191,8 +1251,8 @@ func (c *internalClient) GetMetastoreSummary(ctx context.Context, req *GetMetast // contain zero results while still providing a next_page_token. Clients must // continue reading pages until next_page_token is absent, which is the only // indication that the end of results has been reached. -func (c *internalClient) ListMetastores(ctx context.Context, req *ListMetastoresRequest, opts ...call.Option) (*ListMetastoresResponse, error) { - wireReq, err := listMetastoresRequestToWire(req) +func (c *internalClient) ListMetastores(ctx context.Context, req ListMetastoresRequest, opts ...call.Option) (*ListMetastoresResponse, error) { + wireReq, err := listMetastoresRequestToWire(&req) if err != nil { return nil, err } @@ -1262,7 +1322,7 @@ func (c *internalClient) ListMetastores(ctx context.Context, req *ListMetastores // // For example: // -// for item, err := range c.ListMetastoresIter(ctx, &ListMetastoresRequest{}) { +// for item, err := range c.ListMetastoresIter(ctx, ListMetastoresRequest{}) { // if err != nil { // return err // } @@ -1274,16 +1334,13 @@ func (c *internalClient) ListMetastores(ctx context.Context, req *ListMetastores // // Callers who need custom pagination logic should use // ListMetastores directly. -func (c *internalClient) ListMetastoresIter(ctx context.Context, req *ListMetastoresRequest, opts ...call.Option) iter.Seq2[*MetastoreInfo, error] { +func (c *internalClient) ListMetastoresIter(ctx context.Context, req ListMetastoresRequest, opts ...call.Option) iter.Seq2[*MetastoreInfo, error] { return func(yield func(*MetastoreInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListMetastoresRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListMetastores(ctx, &pageReq, opts...) + resp, err := c.ListMetastores(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -1304,8 +1361,8 @@ func (c *internalClient) ListMetastoresIter(ctx context.Context, req *ListMetast // Updates information for a specific metastore. The caller must be a metastore // admin. If the __owner__ field is set to the empty string (**""**), the // ownership is updated to the System User. -func (c *internalClient) UpdateMetastore(ctx context.Context, req *UpdateMetastoreRequest, opts ...call.Option) (*MetastoreInfo, error) { - wireReq, err := updateMetastoreRequestToWire(req) +func (c *internalClient) UpdateMetastore(ctx context.Context, req UpdateMetastoreRequest, opts ...call.Option) (*MetastoreInfo, error) { + wireReq, err := updateMetastoreRequestToWire(&req) if err != nil { return nil, err } @@ -1326,7 +1383,11 @@ func (c *internalClient) UpdateMetastore(ctx context.Context, req *UpdateMetasto } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/metastores/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -1377,8 +1438,8 @@ func (c *internalClient) UpdateMetastore(ctx context.Context, req *UpdateMetasto // the Workspace is already assigned a metastore. The caller must be an account // admin to update __metastore_id__; otherwise, the caller can be a Workspace // admin. -func (c *internalClient) UpdateMetastoreAssignment(ctx context.Context, req *UpdateMetastoreAssignmentRequest, opts ...call.Option) (*UpdateMetastoreAssignmentResponse, error) { - wireReq, err := updateMetastoreAssignmentRequestToWire(req) +func (c *internalClient) UpdateMetastoreAssignment(ctx context.Context, req UpdateMetastoreAssignmentRequest, opts ...call.Option) (*UpdateMetastoreAssignmentResponse, error) { + wireReq, err := updateMetastoreAssignmentRequestToWire(&req) if err != nil { return nil, err } @@ -1399,7 +1460,11 @@ func (c *internalClient) UpdateMetastoreAssignment(ctx context.Context, req *Upd } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/workspaces/") - pb.singleSegment(*req.WorkspaceId) + if req.WorkspaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.WorkspaceId) + } pb.literal("/metastore") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} diff --git a/uc/metastores/v1/genhelper.go b/uc/metastores/v1/genhelper.go old mode 100755 new mode 100644 index 1767964..bf84394 --- a/uc/metastores/v1/genhelper.go +++ b/uc/metastores/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/metastores/v1/wire.go b/uc/metastores/v1/wire.go old mode 100755 new mode 100644 index 2b9b807..abbeb3d --- a/uc/metastores/v1/wire.go +++ b/uc/metastores/v1/wire.go @@ -3,12 +3,58 @@ package metastores import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type accountsCreateMetastoreAssignmentRequestWire struct { AccountId *string `json:"account_id,omitempty"` - WorkspaceId *int64 `json:"workspace_id,omitempty"` + WorkspaceId *wireInt64 `json:"workspace_id,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` MetastoreAssignment *metastoreAssignmentWire `json:"metastore_assignment,omitempty"` } @@ -17,13 +63,17 @@ func accountsCreateMetastoreAssignmentRequestToWire(v *AccountsCreateMetastoreAs if v == nil { return nil, nil } + workspaceIdWireValue, err := int64ToWire(v.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AccountsCreateMetastoreAssignmentRequest.WorkspaceId", err) + } metastoreAssignmentWireValue, err := metastoreAssignmentToWire(v.MetastoreAssignment) if err != nil { return nil, fmt.Errorf("%s: %w", "AccountsCreateMetastoreAssignmentRequest.MetastoreAssignment", err) } return &accountsCreateMetastoreAssignmentRequestWire{ AccountId: v.AccountId, - WorkspaceId: v.WorkspaceId, + WorkspaceId: workspaceIdWireValue, MetastoreId: v.MetastoreId, MetastoreAssignment: metastoreAssignmentWireValue, }, nil @@ -134,21 +184,25 @@ func accountsListMetastoresResponseFromWire(w *accountsListMetastoresResponseWir } type accountsListWorkspaceIdsForMetastoreResponseWire struct { - WorkspaceIds []int64 `json:"workspace_ids,omitempty"` + WorkspaceIds []wireInt64 `json:"workspace_ids,omitempty"` } func accountsListWorkspaceIdsForMetastoreResponseFromWire(w *accountsListWorkspaceIdsForMetastoreResponseWire) (*AccountsListWorkspaceIdsForMetastoreResponse, error) { if w == nil { return nil, nil } + workspaceIdsPublicValue, err := convertSlice(w.WorkspaceIds, int64FromWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AccountsListWorkspaceIdsForMetastoreResponse.WorkspaceIds", err) + } return &AccountsListWorkspaceIdsForMetastoreResponse{ - WorkspaceIds: w.WorkspaceIds, + WorkspaceIds: workspaceIdsPublicValue, }, nil } type accountsUpdateMetastoreAssignmentRequestWire struct { AccountId *string `json:"account_id,omitempty"` - WorkspaceId *int64 `json:"workspace_id,omitempty"` + WorkspaceId *wireInt64 `json:"workspace_id,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` MetastoreAssignment *metastoreAssignmentWire `json:"metastore_assignment,omitempty"` } @@ -157,13 +211,17 @@ func accountsUpdateMetastoreAssignmentRequestToWire(v *AccountsUpdateMetastoreAs if v == nil { return nil, nil } + workspaceIdWireValue, err := int64ToWire(v.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "AccountsUpdateMetastoreAssignmentRequest.WorkspaceId", err) + } metastoreAssignmentWireValue, err := metastoreAssignmentToWire(v.MetastoreAssignment) if err != nil { return nil, fmt.Errorf("%s: %w", "AccountsUpdateMetastoreAssignmentRequest.MetastoreAssignment", err) } return &accountsUpdateMetastoreAssignmentRequestWire{ AccountId: v.AccountId, - WorkspaceId: v.WorkspaceId, + WorkspaceId: workspaceIdWireValue, MetastoreId: v.MetastoreId, MetastoreAssignment: metastoreAssignmentWireValue, }, nil @@ -213,15 +271,15 @@ type createAccountsMetastoreWire struct { DefaultDataAccessConfigId *string `json:"default_data_access_config_id,omitempty"` StorageRootCredentialId *string `json:"storage_root_credential_id,omitempty"` DeltaSharingScope DeltaSharingScope_Enum `json:"delta_sharing_scope,omitempty"` - DeltaSharingRecipientTokenLifetimeInSeconds *int64 `json:"delta_sharing_recipient_token_lifetime_in_seconds,omitempty"` + DeltaSharingRecipientTokenLifetimeInSeconds *wireInt64 `json:"delta_sharing_recipient_token_lifetime_in_seconds,omitempty"` DeltaSharingOrganizationName *string `json:"delta_sharing_organization_name,omitempty"` Owner *string `json:"owner,omitempty"` PrivilegeModelVersion *string `json:"privilege_model_version,omitempty"` Region *string `json:"region,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` StorageRootCredentialName *string `json:"storage_root_credential_name,omitempty"` Cloud *string `json:"cloud,omitempty"` @@ -233,21 +291,33 @@ func createAccountsMetastoreToWire(v *CreateAccountsMetastore) (*createAccountsM if v == nil { return nil, nil } + deltaSharingRecipientTokenLifetimeInSecondsWireValue, err := int64ToWire(v.DeltaSharingRecipientTokenLifetimeInSeconds) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateAccountsMetastore.DeltaSharingRecipientTokenLifetimeInSeconds", err) + } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateAccountsMetastore.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateAccountsMetastore.UpdatedAt", err) + } return &createAccountsMetastoreWire{ Name: v.Name, StorageRoot: v.StorageRoot, DefaultDataAccessConfigId: v.DefaultDataAccessConfigId, StorageRootCredentialId: v.StorageRootCredentialId, DeltaSharingScope: v.DeltaSharingScope, - DeltaSharingRecipientTokenLifetimeInSeconds: v.DeltaSharingRecipientTokenLifetimeInSeconds, + DeltaSharingRecipientTokenLifetimeInSeconds: deltaSharingRecipientTokenLifetimeInSecondsWireValue, DeltaSharingOrganizationName: v.DeltaSharingOrganizationName, Owner: v.Owner, PrivilegeModelVersion: v.PrivilegeModelVersion, Region: v.Region, MetastoreId: v.MetastoreId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, StorageRootCredentialName: v.StorageRootCredentialName, Cloud: v.Cloud, @@ -257,17 +327,21 @@ func createAccountsMetastoreToWire(v *CreateAccountsMetastore) (*createAccountsM } type createMetastoreAssignmentRequestWire struct { - WorkspaceId *int64 `json:"workspace_id,omitempty"` - MetastoreId *string `json:"metastore_id,omitempty"` - DefaultCatalogName *string `json:"default_catalog_name,omitempty"` + WorkspaceId *wireInt64 `json:"workspace_id,omitempty"` + MetastoreId *string `json:"metastore_id,omitempty"` + DefaultCatalogName *string `json:"default_catalog_name,omitempty"` } func createMetastoreAssignmentRequestToWire(v *CreateMetastoreAssignmentRequest) (*createMetastoreAssignmentRequestWire, error) { if v == nil { return nil, nil } + workspaceIdWireValue, err := int64ToWire(v.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateMetastoreAssignmentRequest.WorkspaceId", err) + } return &createMetastoreAssignmentRequestWire{ - WorkspaceId: v.WorkspaceId, + WorkspaceId: workspaceIdWireValue, MetastoreId: v.MetastoreId, DefaultCatalogName: v.DefaultCatalogName, }, nil @@ -279,15 +353,15 @@ type createMetastoreRequestWire struct { DefaultDataAccessConfigId *string `json:"default_data_access_config_id,omitempty"` StorageRootCredentialId *string `json:"storage_root_credential_id,omitempty"` DeltaSharingScope DeltaSharingScope_Enum `json:"delta_sharing_scope,omitempty"` - DeltaSharingRecipientTokenLifetimeInSeconds *int64 `json:"delta_sharing_recipient_token_lifetime_in_seconds,omitempty"` + DeltaSharingRecipientTokenLifetimeInSeconds *wireInt64 `json:"delta_sharing_recipient_token_lifetime_in_seconds,omitempty"` DeltaSharingOrganizationName *string `json:"delta_sharing_organization_name,omitempty"` Owner *string `json:"owner,omitempty"` PrivilegeModelVersion *string `json:"privilege_model_version,omitempty"` Region *string `json:"region,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` StorageRootCredentialName *string `json:"storage_root_credential_name,omitempty"` Cloud *string `json:"cloud,omitempty"` @@ -299,21 +373,33 @@ func createMetastoreRequestToWire(v *CreateMetastoreRequest) (*createMetastoreRe if v == nil { return nil, nil } + deltaSharingRecipientTokenLifetimeInSecondsWireValue, err := int64ToWire(v.DeltaSharingRecipientTokenLifetimeInSeconds) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateMetastoreRequest.DeltaSharingRecipientTokenLifetimeInSeconds", err) + } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateMetastoreRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateMetastoreRequest.UpdatedAt", err) + } return &createMetastoreRequestWire{ Name: v.Name, StorageRoot: v.StorageRoot, DefaultDataAccessConfigId: v.DefaultDataAccessConfigId, StorageRootCredentialId: v.StorageRootCredentialId, DeltaSharingScope: v.DeltaSharingScope, - DeltaSharingRecipientTokenLifetimeInSeconds: v.DeltaSharingRecipientTokenLifetimeInSeconds, + DeltaSharingRecipientTokenLifetimeInSeconds: deltaSharingRecipientTokenLifetimeInSecondsWireValue, DeltaSharingOrganizationName: v.DeltaSharingOrganizationName, Owner: v.Owner, PrivilegeModelVersion: v.PrivilegeModelVersion, Region: v.Region, MetastoreId: v.MetastoreId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, StorageRootCredentialName: v.StorageRootCredentialName, Cloud: v.Cloud, @@ -323,16 +409,20 @@ func createMetastoreRequestToWire(v *CreateMetastoreRequest) (*createMetastoreRe } type deleteMetastoreAssignmentRequestWire struct { - WorkspaceId *int64 `json:"workspace_id,omitempty"` - MetastoreId *string `json:"metastore_id,omitempty"` + WorkspaceId *wireInt64 `json:"workspace_id,omitempty"` + MetastoreId *string `json:"metastore_id,omitempty"` } func deleteMetastoreAssignmentRequestToWire(v *DeleteMetastoreAssignmentRequest) (*deleteMetastoreAssignmentRequestWire, error) { if v == nil { return nil, nil } + workspaceIdWireValue, err := int64ToWire(v.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "DeleteMetastoreAssignmentRequest.WorkspaceId", err) + } return &deleteMetastoreAssignmentRequestWire{ - WorkspaceId: v.WorkspaceId, + WorkspaceId: workspaceIdWireValue, MetastoreId: v.MetastoreId, }, nil } @@ -363,13 +453,13 @@ type getMetastoreSummaryResponseWire struct { StorageRootCredentialName *string `json:"storage_root_credential_name,omitempty"` PrivilegeModelVersion *string `json:"privilege_model_version,omitempty"` DeltaSharingScope DeltaSharingScope_Enum `json:"delta_sharing_scope,omitempty"` - DeltaSharingRecipientTokenLifetimeInSeconds *int64 `json:"delta_sharing_recipient_token_lifetime_in_seconds,omitempty"` + DeltaSharingRecipientTokenLifetimeInSeconds *wireInt64 `json:"delta_sharing_recipient_token_lifetime_in_seconds,omitempty"` DeltaSharingOrganizationName *string `json:"delta_sharing_organization_name,omitempty"` StorageRoot *string `json:"storage_root,omitempty"` Owner *string `json:"owner,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` ExternalAccessEnabled *bool `json:"external_access_enabled,omitempty"` } @@ -378,6 +468,18 @@ func getMetastoreSummaryResponseFromWire(w *getMetastoreSummaryResponseWire) (*G if w == nil { return nil, nil } + deltaSharingRecipientTokenLifetimeInSecondsPublicValue, err := int64FromWire(w.DeltaSharingRecipientTokenLifetimeInSeconds) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetMetastoreSummaryResponse.DeltaSharingRecipientTokenLifetimeInSeconds", err) + } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetMetastoreSummaryResponse.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetMetastoreSummaryResponse.UpdatedAt", err) + } return &GetMetastoreSummaryResponse{ MetastoreId: w.MetastoreId, Name: w.Name, @@ -389,13 +491,13 @@ func getMetastoreSummaryResponseFromWire(w *getMetastoreSummaryResponseWire) (*G StorageRootCredentialName: w.StorageRootCredentialName, PrivilegeModelVersion: w.PrivilegeModelVersion, DeltaSharingScope: w.DeltaSharingScope, - DeltaSharingRecipientTokenLifetimeInSeconds: w.DeltaSharingRecipientTokenLifetimeInSeconds, + DeltaSharingRecipientTokenLifetimeInSeconds: deltaSharingRecipientTokenLifetimeInSecondsPublicValue, DeltaSharingOrganizationName: w.DeltaSharingOrganizationName, StorageRoot: w.StorageRoot, Owner: w.Owner, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, ExternalAccessEnabled: w.ExternalAccessEnabled, }, nil @@ -436,17 +538,21 @@ func listMetastoresResponseFromWire(w *listMetastoresResponseWire) (*ListMetasto } type metastoreAssignmentWire struct { - WorkspaceId *int64 `json:"workspace_id,omitempty"` - MetastoreId *string `json:"metastore_id,omitempty"` - DefaultCatalogName *string `json:"default_catalog_name,omitempty"` + WorkspaceId *wireInt64 `json:"workspace_id,omitempty"` + MetastoreId *string `json:"metastore_id,omitempty"` + DefaultCatalogName *string `json:"default_catalog_name,omitempty"` } func metastoreAssignmentToWire(v *MetastoreAssignment) (*metastoreAssignmentWire, error) { if v == nil { return nil, nil } + workspaceIdWireValue, err := int64ToWire(v.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "MetastoreAssignment.WorkspaceId", err) + } return &metastoreAssignmentWire{ - WorkspaceId: v.WorkspaceId, + WorkspaceId: workspaceIdWireValue, MetastoreId: v.MetastoreId, DefaultCatalogName: v.DefaultCatalogName, }, nil @@ -456,8 +562,12 @@ func metastoreAssignmentFromWire(w *metastoreAssignmentWire) (*MetastoreAssignme if w == nil { return nil, nil } + workspaceIdPublicValue, err := int64FromWire(w.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "MetastoreAssignment.WorkspaceId", err) + } return &MetastoreAssignment{ - WorkspaceId: w.WorkspaceId, + WorkspaceId: workspaceIdPublicValue, MetastoreId: w.MetastoreId, DefaultCatalogName: w.DefaultCatalogName, }, nil @@ -469,15 +579,15 @@ type metastoreInfoWire struct { DefaultDataAccessConfigId *string `json:"default_data_access_config_id,omitempty"` StorageRootCredentialId *string `json:"storage_root_credential_id,omitempty"` DeltaSharingScope DeltaSharingScope_Enum `json:"delta_sharing_scope,omitempty"` - DeltaSharingRecipientTokenLifetimeInSeconds *int64 `json:"delta_sharing_recipient_token_lifetime_in_seconds,omitempty"` + DeltaSharingRecipientTokenLifetimeInSeconds *wireInt64 `json:"delta_sharing_recipient_token_lifetime_in_seconds,omitempty"` DeltaSharingOrganizationName *string `json:"delta_sharing_organization_name,omitempty"` Owner *string `json:"owner,omitempty"` PrivilegeModelVersion *string `json:"privilege_model_version,omitempty"` Region *string `json:"region,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` StorageRootCredentialName *string `json:"storage_root_credential_name,omitempty"` Cloud *string `json:"cloud,omitempty"` @@ -489,21 +599,33 @@ func metastoreInfoFromWire(w *metastoreInfoWire) (*MetastoreInfo, error) { if w == nil { return nil, nil } + deltaSharingRecipientTokenLifetimeInSecondsPublicValue, err := int64FromWire(w.DeltaSharingRecipientTokenLifetimeInSeconds) + if err != nil { + return nil, fmt.Errorf("%s: %w", "MetastoreInfo.DeltaSharingRecipientTokenLifetimeInSeconds", err) + } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "MetastoreInfo.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "MetastoreInfo.UpdatedAt", err) + } return &MetastoreInfo{ Name: w.Name, StorageRoot: w.StorageRoot, DefaultDataAccessConfigId: w.DefaultDataAccessConfigId, StorageRootCredentialId: w.StorageRootCredentialId, DeltaSharingScope: w.DeltaSharingScope, - DeltaSharingRecipientTokenLifetimeInSeconds: w.DeltaSharingRecipientTokenLifetimeInSeconds, + DeltaSharingRecipientTokenLifetimeInSeconds: deltaSharingRecipientTokenLifetimeInSecondsPublicValue, DeltaSharingOrganizationName: w.DeltaSharingOrganizationName, Owner: w.Owner, PrivilegeModelVersion: w.PrivilegeModelVersion, Region: w.Region, MetastoreId: w.MetastoreId, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, StorageRootCredentialName: w.StorageRootCredentialName, Cloud: w.Cloud, @@ -518,15 +640,15 @@ type updateAccountsMetastoreWire struct { DefaultDataAccessConfigId *string `json:"default_data_access_config_id,omitempty"` StorageRootCredentialId *string `json:"storage_root_credential_id,omitempty"` DeltaSharingScope DeltaSharingScope_Enum `json:"delta_sharing_scope,omitempty"` - DeltaSharingRecipientTokenLifetimeInSeconds *int64 `json:"delta_sharing_recipient_token_lifetime_in_seconds,omitempty"` + DeltaSharingRecipientTokenLifetimeInSeconds *wireInt64 `json:"delta_sharing_recipient_token_lifetime_in_seconds,omitempty"` DeltaSharingOrganizationName *string `json:"delta_sharing_organization_name,omitempty"` Owner *string `json:"owner,omitempty"` PrivilegeModelVersion *string `json:"privilege_model_version,omitempty"` Region *string `json:"region,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` StorageRootCredentialName *string `json:"storage_root_credential_name,omitempty"` Cloud *string `json:"cloud,omitempty"` @@ -538,21 +660,33 @@ func updateAccountsMetastoreToWire(v *UpdateAccountsMetastore) (*updateAccountsM if v == nil { return nil, nil } + deltaSharingRecipientTokenLifetimeInSecondsWireValue, err := int64ToWire(v.DeltaSharingRecipientTokenLifetimeInSeconds) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateAccountsMetastore.DeltaSharingRecipientTokenLifetimeInSeconds", err) + } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateAccountsMetastore.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateAccountsMetastore.UpdatedAt", err) + } return &updateAccountsMetastoreWire{ Name: v.Name, StorageRoot: v.StorageRoot, DefaultDataAccessConfigId: v.DefaultDataAccessConfigId, StorageRootCredentialId: v.StorageRootCredentialId, DeltaSharingScope: v.DeltaSharingScope, - DeltaSharingRecipientTokenLifetimeInSeconds: v.DeltaSharingRecipientTokenLifetimeInSeconds, + DeltaSharingRecipientTokenLifetimeInSeconds: deltaSharingRecipientTokenLifetimeInSecondsWireValue, DeltaSharingOrganizationName: v.DeltaSharingOrganizationName, Owner: v.Owner, PrivilegeModelVersion: v.PrivilegeModelVersion, Region: v.Region, MetastoreId: v.MetastoreId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, StorageRootCredentialName: v.StorageRootCredentialName, Cloud: v.Cloud, @@ -562,17 +696,21 @@ func updateAccountsMetastoreToWire(v *UpdateAccountsMetastore) (*updateAccountsM } type updateMetastoreAssignmentRequestWire struct { - WorkspaceId *int64 `json:"workspace_id,omitempty"` - MetastoreId *string `json:"metastore_id,omitempty"` - DefaultCatalogName *string `json:"default_catalog_name,omitempty"` + WorkspaceId *wireInt64 `json:"workspace_id,omitempty"` + MetastoreId *string `json:"metastore_id,omitempty"` + DefaultCatalogName *string `json:"default_catalog_name,omitempty"` } func updateMetastoreAssignmentRequestToWire(v *UpdateMetastoreAssignmentRequest) (*updateMetastoreAssignmentRequestWire, error) { if v == nil { return nil, nil } + workspaceIdWireValue, err := int64ToWire(v.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateMetastoreAssignmentRequest.WorkspaceId", err) + } return &updateMetastoreAssignmentRequestWire{ - WorkspaceId: v.WorkspaceId, + WorkspaceId: workspaceIdWireValue, MetastoreId: v.MetastoreId, DefaultCatalogName: v.DefaultCatalogName, }, nil @@ -586,15 +724,15 @@ type updateMetastoreRequestWire struct { DefaultDataAccessConfigId *string `json:"default_data_access_config_id,omitempty"` StorageRootCredentialId *string `json:"storage_root_credential_id,omitempty"` DeltaSharingScope DeltaSharingScope_Enum `json:"delta_sharing_scope,omitempty"` - DeltaSharingRecipientTokenLifetimeInSeconds *int64 `json:"delta_sharing_recipient_token_lifetime_in_seconds,omitempty"` + DeltaSharingRecipientTokenLifetimeInSeconds *wireInt64 `json:"delta_sharing_recipient_token_lifetime_in_seconds,omitempty"` DeltaSharingOrganizationName *string `json:"delta_sharing_organization_name,omitempty"` Owner *string `json:"owner,omitempty"` PrivilegeModelVersion *string `json:"privilege_model_version,omitempty"` Region *string `json:"region,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` StorageRootCredentialName *string `json:"storage_root_credential_name,omitempty"` Cloud *string `json:"cloud,omitempty"` @@ -606,6 +744,18 @@ func updateMetastoreRequestToWire(v *UpdateMetastoreRequest) (*updateMetastoreRe if v == nil { return nil, nil } + deltaSharingRecipientTokenLifetimeInSecondsWireValue, err := int64ToWire(v.DeltaSharingRecipientTokenLifetimeInSeconds) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateMetastoreRequest.DeltaSharingRecipientTokenLifetimeInSeconds", err) + } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateMetastoreRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateMetastoreRequest.UpdatedAt", err) + } return &updateMetastoreRequestWire{ Id: v.Id, NewName: v.NewName, @@ -614,15 +764,15 @@ func updateMetastoreRequestToWire(v *UpdateMetastoreRequest) (*updateMetastoreRe DefaultDataAccessConfigId: v.DefaultDataAccessConfigId, StorageRootCredentialId: v.StorageRootCredentialId, DeltaSharingScope: v.DeltaSharingScope, - DeltaSharingRecipientTokenLifetimeInSeconds: v.DeltaSharingRecipientTokenLifetimeInSeconds, + DeltaSharingRecipientTokenLifetimeInSeconds: deltaSharingRecipientTokenLifetimeInSecondsWireValue, DeltaSharingOrganizationName: v.DeltaSharingOrganizationName, Owner: v.Owner, PrivilegeModelVersion: v.PrivilegeModelVersion, Region: v.Region, MetastoreId: v.MetastoreId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, StorageRootCredentialName: v.StorageRootCredentialName, Cloud: v.Cloud, diff --git a/uc/onlinetables/CHANGELOG.md b/uc/onlinetables/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/onlinetables/CHANGELOG.md +++ b/uc/onlinetables/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/onlinetables/go.mod b/uc/onlinetables/go.mod index 2e436ff..569d69b 100644 --- a/uc/onlinetables/go.mod +++ b/uc/onlinetables/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/onlinetables/internal/version.go b/uc/onlinetables/internal/version.go index 90c0e69..c984017 100644 --- a/uc/onlinetables/internal/version.go +++ b/uc/onlinetables/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-onlinetables" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/onlinetables/v1/client.go b/uc/onlinetables/v1/client.go old mode 100755 new mode 100644 index ec11ab6..8fbe34b --- a/uc/onlinetables/v1/client.go +++ b/uc/onlinetables/v1/client.go @@ -76,8 +76,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Create a new Online Table. -func (c *internalClient) createOnlineTableBase(ctx context.Context, req *CreateOnlineTableRequest, opts ...call.Option) (*OnlineTable, error) { - wireReq, err := createOnlineTableRequestToWire(req) +func (c *internalClient) createOnlineTableBase(ctx context.Context, req CreateOnlineTableRequest, opts ...call.Option) (*OnlineTable, error) { + wireReq, err := createOnlineTableRequestToWire(&req) if err != nil { return nil, err } @@ -142,7 +142,7 @@ func (c *internalClient) createOnlineTableBase(ctx context.Context, req *CreateO } // Create a new Online Table. -func (c *internalClient) CreateOnlineTable(ctx context.Context, req *CreateOnlineTableRequest, opts ...call.Option) (*CreateOnlineTableWaiter, error) { +func (c *internalClient) CreateOnlineTable(ctx context.Context, req CreateOnlineTableRequest, opts ...call.Option) (*CreateOnlineTableWaiter, error) { resp, err := c.createOnlineTableBase(ctx, req, opts...) if err != nil { return nil, err @@ -158,13 +158,18 @@ func (c *internalClient) CreateOnlineTable(ctx context.Context, req *CreateOnlin // CreateOnlineTableWaiter tracks the state of the operation started by CreateOnlineTable. type CreateOnlineTableWaiter struct { - poll func(context.Context, *GetOnlineTableRequest, ...call.Option) (*OnlineTable, error) + poll func(context.Context, GetOnlineTableRequest, ...call.Option) (*OnlineTable, error) name string } +// GetName returns the Name value used to identify the operation. +func (w *CreateOnlineTableWaiter) GetName() string { + return w.name +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *CreateOnlineTableWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetOnlineTableRequest{ + pollResp, err := w.poll(ctx, GetOnlineTableRequest{ Name: &w.name, }, opts...) if err != nil { @@ -189,7 +194,7 @@ func (w *CreateOnlineTableWaiter) Done(ctx context.Context, opts ...call.Option) func (w *CreateOnlineTableWaiter) Wait(ctx context.Context, opts ...lro.Option) (*OnlineTable, error) { var result *OnlineTable poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetOnlineTableRequest{ + pollResp, err := w.poll(ctx, GetOnlineTableRequest{ Name: &w.name, }) if err != nil { @@ -222,7 +227,7 @@ func (w *CreateOnlineTableWaiter) Wait(ctx context.Context, opts ...lro.Option) // Delete an online table. Warning: This will delete all the data in the online // table. If the source Delta table was deleted or modified since this Online // Table was created, this will lose the data forever! -func (c *internalClient) DeleteOnlineTable(ctx context.Context, req *DeleteOnlineTableRequest, opts ...call.Option) error { +func (c *internalClient) DeleteOnlineTable(ctx context.Context, req DeleteOnlineTableRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -236,7 +241,11 @@ func (c *internalClient) DeleteOnlineTable(ctx context.Context, req *DeleteOnlin } pb := pathBuilder{} pb.literal("/api/2.0/online-tables/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -273,7 +282,7 @@ func (c *internalClient) DeleteOnlineTable(ctx context.Context, req *DeleteOnlin } // Get information about an existing online table and its status. -func (c *internalClient) GetOnlineTable(ctx context.Context, req *GetOnlineTableRequest, opts ...call.Option) (*OnlineTable, error) { +func (c *internalClient) GetOnlineTable(ctx context.Context, req GetOnlineTableRequest, opts ...call.Option) (*OnlineTable, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -287,7 +296,11 @@ func (c *internalClient) GetOnlineTable(ctx context.Context, req *GetOnlineTable } pb := pathBuilder{} pb.literal("/api/2.0/online-tables/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/uc/onlinetables/v1/genhelper.go b/uc/onlinetables/v1/genhelper.go old mode 100755 new mode 100644 index 7437b9d..920ee4c --- a/uc/onlinetables/v1/genhelper.go +++ b/uc/onlinetables/v1/genhelper.go @@ -165,11 +165,12 @@ func executeWait(ctx context.Context, operation func(context.Context) error, opt ) } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -182,13 +183,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/onlinetables/v1/wire.go b/uc/onlinetables/v1/wire.go old mode 100755 new mode 100644 index 19b11fb..4950bc1 --- a/uc/onlinetables/v1/wire.go +++ b/uc/onlinetables/v1/wire.go @@ -3,13 +3,59 @@ package onlinetables import ( + "bytes" + "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type continuousUpdateStatusWire struct { - LastProcessedCommitVersion *int64 `json:"last_processed_commit_version,omitempty"` + LastProcessedCommitVersion *wireInt64 `json:"last_processed_commit_version,omitempty"` Timestamp *types.Time `json:"timestamp,omitempty"` InitialPipelineSyncProgress *pipelineProgressWire `json:"initial_pipeline_sync_progress,omitempty"` } @@ -18,12 +64,16 @@ func continuousUpdateStatusToWire(v *ContinuousUpdateStatus) (*continuousUpdateS if v == nil { return nil, nil } + lastProcessedCommitVersionWireValue, err := int64ToWire(v.LastProcessedCommitVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ContinuousUpdateStatus.LastProcessedCommitVersion", err) + } initialPipelineSyncProgressWireValue, err := pipelineProgressToWire(v.InitialPipelineSyncProgress) if err != nil { return nil, fmt.Errorf("%s: %w", "ContinuousUpdateStatus.InitialPipelineSyncProgress", err) } return &continuousUpdateStatusWire{ - LastProcessedCommitVersion: v.LastProcessedCommitVersion, + LastProcessedCommitVersion: lastProcessedCommitVersionWireValue, Timestamp: v.Timestamp, InitialPipelineSyncProgress: initialPipelineSyncProgressWireValue, }, nil @@ -33,12 +83,16 @@ func continuousUpdateStatusFromWire(w *continuousUpdateStatusWire) (*ContinuousU if w == nil { return nil, nil } + lastProcessedCommitVersionPublicValue, err := int64FromWire(w.LastProcessedCommitVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ContinuousUpdateStatus.LastProcessedCommitVersion", err) + } initialPipelineSyncProgressPublicValue, err := pipelineProgressFromWire(w.InitialPipelineSyncProgress) if err != nil { return nil, fmt.Errorf("%s: %w", "ContinuousUpdateStatus.InitialPipelineSyncProgress", err) } return &ContinuousUpdateStatus{ - LastProcessedCommitVersion: w.LastProcessedCommitVersion, + LastProcessedCommitVersion: lastProcessedCommitVersionPublicValue, Timestamp: w.Timestamp, InitialPipelineSyncProgress: initialPipelineSyncProgressPublicValue, }, nil @@ -62,7 +116,7 @@ func createOnlineTableRequestToWire(v *CreateOnlineTableRequest) (*createOnlineT } type failedStatusWire struct { - LastProcessedCommitVersion *int64 `json:"last_processed_commit_version,omitempty"` + LastProcessedCommitVersion *wireInt64 `json:"last_processed_commit_version,omitempty"` Timestamp *types.Time `json:"timestamp,omitempty"` } @@ -70,8 +124,12 @@ func failedStatusToWire(v *FailedStatus) (*failedStatusWire, error) { if v == nil { return nil, nil } + lastProcessedCommitVersionWireValue, err := int64ToWire(v.LastProcessedCommitVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FailedStatus.LastProcessedCommitVersion", err) + } return &failedStatusWire{ - LastProcessedCommitVersion: v.LastProcessedCommitVersion, + LastProcessedCommitVersion: lastProcessedCommitVersionWireValue, Timestamp: v.Timestamp, }, nil } @@ -80,8 +138,12 @@ func failedStatusFromWire(w *failedStatusWire) (*FailedStatus, error) { if w == nil { return nil, nil } + lastProcessedCommitVersionPublicValue, err := int64FromWire(w.LastProcessedCommitVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "FailedStatus.LastProcessedCommitVersion", err) + } return &FailedStatus{ - LastProcessedCommitVersion: w.LastProcessedCommitVersion, + LastProcessedCommitVersion: lastProcessedCommitVersionPublicValue, Timestamp: w.Timestamp, }, nil } @@ -376,21 +438,33 @@ func onlineTableStatusFromWire(w *onlineTableStatusWire) (*OnlineTableStatus, er } type pipelineProgressWire struct { - LatestVersionCurrentlyProcessing *int64 `json:"latest_version_currently_processing,omitempty"` - SyncedRowCount *int64 `json:"synced_row_count,omitempty"` - TotalRowCount *int64 `json:"total_row_count,omitempty"` - SyncProgressCompletion *float64 `json:"sync_progress_completion,omitempty"` - EstimatedCompletionTimeSeconds *float64 `json:"estimated_completion_time_seconds,omitempty"` + LatestVersionCurrentlyProcessing *wireInt64 `json:"latest_version_currently_processing,omitempty"` + SyncedRowCount *wireInt64 `json:"synced_row_count,omitempty"` + TotalRowCount *wireInt64 `json:"total_row_count,omitempty"` + SyncProgressCompletion *float64 `json:"sync_progress_completion,omitempty"` + EstimatedCompletionTimeSeconds *float64 `json:"estimated_completion_time_seconds,omitempty"` } func pipelineProgressToWire(v *PipelineProgress) (*pipelineProgressWire, error) { if v == nil { return nil, nil } + latestVersionCurrentlyProcessingWireValue, err := int64ToWire(v.LatestVersionCurrentlyProcessing) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PipelineProgress.LatestVersionCurrentlyProcessing", err) + } + syncedRowCountWireValue, err := int64ToWire(v.SyncedRowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PipelineProgress.SyncedRowCount", err) + } + totalRowCountWireValue, err := int64ToWire(v.TotalRowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PipelineProgress.TotalRowCount", err) + } return &pipelineProgressWire{ - LatestVersionCurrentlyProcessing: v.LatestVersionCurrentlyProcessing, - SyncedRowCount: v.SyncedRowCount, - TotalRowCount: v.TotalRowCount, + LatestVersionCurrentlyProcessing: latestVersionCurrentlyProcessingWireValue, + SyncedRowCount: syncedRowCountWireValue, + TotalRowCount: totalRowCountWireValue, SyncProgressCompletion: v.SyncProgressCompletion, EstimatedCompletionTimeSeconds: v.EstimatedCompletionTimeSeconds, }, nil @@ -400,10 +474,22 @@ func pipelineProgressFromWire(w *pipelineProgressWire) (*PipelineProgress, error if w == nil { return nil, nil } + latestVersionCurrentlyProcessingPublicValue, err := int64FromWire(w.LatestVersionCurrentlyProcessing) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PipelineProgress.LatestVersionCurrentlyProcessing", err) + } + syncedRowCountPublicValue, err := int64FromWire(w.SyncedRowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PipelineProgress.SyncedRowCount", err) + } + totalRowCountPublicValue, err := int64FromWire(w.TotalRowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PipelineProgress.TotalRowCount", err) + } return &PipelineProgress{ - LatestVersionCurrentlyProcessing: w.LatestVersionCurrentlyProcessing, - SyncedRowCount: w.SyncedRowCount, - TotalRowCount: w.TotalRowCount, + LatestVersionCurrentlyProcessing: latestVersionCurrentlyProcessingPublicValue, + SyncedRowCount: syncedRowCountPublicValue, + TotalRowCount: totalRowCountPublicValue, SyncProgressCompletion: w.SyncProgressCompletion, EstimatedCompletionTimeSeconds: w.EstimatedCompletionTimeSeconds, }, nil @@ -440,7 +526,7 @@ func provisioningStatusFromWire(w *provisioningStatusWire) (*ProvisioningStatus, } type triggeredUpdateStatusWire struct { - LastProcessedCommitVersion *int64 `json:"last_processed_commit_version,omitempty"` + LastProcessedCommitVersion *wireInt64 `json:"last_processed_commit_version,omitempty"` Timestamp *types.Time `json:"timestamp,omitempty"` TriggeredUpdateProgress *pipelineProgressWire `json:"triggered_update_progress,omitempty"` } @@ -449,12 +535,16 @@ func triggeredUpdateStatusToWire(v *TriggeredUpdateStatus) (*triggeredUpdateStat if v == nil { return nil, nil } + lastProcessedCommitVersionWireValue, err := int64ToWire(v.LastProcessedCommitVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TriggeredUpdateStatus.LastProcessedCommitVersion", err) + } triggeredUpdateProgressWireValue, err := pipelineProgressToWire(v.TriggeredUpdateProgress) if err != nil { return nil, fmt.Errorf("%s: %w", "TriggeredUpdateStatus.TriggeredUpdateProgress", err) } return &triggeredUpdateStatusWire{ - LastProcessedCommitVersion: v.LastProcessedCommitVersion, + LastProcessedCommitVersion: lastProcessedCommitVersionWireValue, Timestamp: v.Timestamp, TriggeredUpdateProgress: triggeredUpdateProgressWireValue, }, nil @@ -464,12 +554,16 @@ func triggeredUpdateStatusFromWire(w *triggeredUpdateStatusWire) (*TriggeredUpda if w == nil { return nil, nil } + lastProcessedCommitVersionPublicValue, err := int64FromWire(w.LastProcessedCommitVersion) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TriggeredUpdateStatus.LastProcessedCommitVersion", err) + } triggeredUpdateProgressPublicValue, err := pipelineProgressFromWire(w.TriggeredUpdateProgress) if err != nil { return nil, fmt.Errorf("%s: %w", "TriggeredUpdateStatus.TriggeredUpdateProgress", err) } return &TriggeredUpdateStatus{ - LastProcessedCommitVersion: w.LastProcessedCommitVersion, + LastProcessedCommitVersion: lastProcessedCommitVersionPublicValue, Timestamp: w.Timestamp, TriggeredUpdateProgress: triggeredUpdateProgressPublicValue, }, nil diff --git a/uc/registeredmodels/CHANGELOG.md b/uc/registeredmodels/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/registeredmodels/CHANGELOG.md +++ b/uc/registeredmodels/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/registeredmodels/go.mod b/uc/registeredmodels/go.mod index 03bb0e9..8a8b798 100644 --- a/uc/registeredmodels/go.mod +++ b/uc/registeredmodels/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/registeredmodels/internal/version.go b/uc/registeredmodels/internal/version.go index 9b3ca28..2bcda9a 100644 --- a/uc/registeredmodels/internal/version.go +++ b/uc/registeredmodels/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-registeredmodels" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/registeredmodels/v1/client.go b/uc/registeredmodels/v1/client.go old mode 100755 new mode 100644 index eb71e65..38e054e --- a/uc/registeredmodels/v1/client.go +++ b/uc/registeredmodels/v1/client.go @@ -86,8 +86,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // parent catalog and the **USE_SCHEMA** privilege on the parent schema. - The // caller must have the **CREATE MODEL** or **CREATE FUNCTION** privilege on the // parent schema. -func (c *internalClient) CreateRegisteredModel(ctx context.Context, req *CreateRegisteredModelRequest, opts ...call.Option) (*RegisteredModelInfo, error) { - wireReq, err := createRegisteredModelRequestToWire(req) +func (c *internalClient) CreateRegisteredModel(ctx context.Context, req CreateRegisteredModelRequest, opts ...call.Option) (*RegisteredModelInfo, error) { + wireReq, err := createRegisteredModelRequestToWire(&req) if err != nil { return nil, err } @@ -158,7 +158,7 @@ func (c *internalClient) CreateRegisteredModel(ctx context.Context, req *CreateR // model. For the latter case, the caller must also be the owner or have the // **USE_CATALOG** privilege on the parent catalog and the **USE_SCHEMA** // privilege on the parent schema. -func (c *internalClient) DeleteModelVersion(ctx context.Context, req *DeleteModelVersionRequest, opts ...call.Option) (*DeleteModelVersionResponse, error) { +func (c *internalClient) DeleteModelVersion(ctx context.Context, req DeleteModelVersionRequest, opts ...call.Option) (*DeleteModelVersionResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -172,9 +172,17 @@ func (c *internalClient) DeleteModelVersion(ctx context.Context, req *DeleteMode } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/models/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } pb.literal("/versions/") - pb.singleSegment(*req.VersionArg) + if req.VersionArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.VersionArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -220,7 +228,7 @@ func (c *internalClient) DeleteModelVersion(ctx context.Context, req *DeleteMode // the latter case, the caller must also be the owner or have the // **USE_CATALOG** privilege on the parent catalog and the **USE_SCHEMA** // privilege on the parent schema. -func (c *internalClient) DeleteRegisteredModel(ctx context.Context, req *DeleteRegisteredModelRequest, opts ...call.Option) (*DeleteRegisteredModelResponse, error) { +func (c *internalClient) DeleteRegisteredModel(ctx context.Context, req DeleteRegisteredModelRequest, opts ...call.Option) (*DeleteRegisteredModelResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -234,7 +242,11 @@ func (c *internalClient) DeleteRegisteredModel(ctx context.Context, req *DeleteR } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/models/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -279,7 +291,7 @@ func (c *internalClient) DeleteRegisteredModel(ctx context.Context, req *DeleteR // the latter case, the caller must also be the owner or have the // **USE_CATALOG** privilege on the parent catalog and the **USE_SCHEMA** // privilege on the parent schema. -func (c *internalClient) DeleteRegisteredModelAlias(ctx context.Context, req *DeleteRegisteredModelAliasRequest, opts ...call.Option) (*DeleteRegisteredModelAliasResponse, error) { +func (c *internalClient) DeleteRegisteredModelAlias(ctx context.Context, req DeleteRegisteredModelAliasRequest, opts ...call.Option) (*DeleteRegisteredModelAliasResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -293,9 +305,17 @@ func (c *internalClient) DeleteRegisteredModelAlias(ctx context.Context, req *De } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/models/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } pb.literal("/aliases/") - pb.singleSegment(*req.AliasArg) + if req.AliasArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.AliasArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -340,8 +360,8 @@ func (c *internalClient) DeleteRegisteredModelAlias(ctx context.Context, req *De // privilege on) the parent registered model. For the latter case, the caller // must also be the owner or have the **USE_CATALOG** privilege on the parent // catalog and the **USE_SCHEMA** privilege on the parent schema. -func (c *internalClient) GetModelVersion(ctx context.Context, req *GetModelVersionRequest, opts ...call.Option) (*ModelVersionInfo, error) { - wireReq, err := getModelVersionRequestToWire(req) +func (c *internalClient) GetModelVersion(ctx context.Context, req GetModelVersionRequest, opts ...call.Option) (*ModelVersionInfo, error) { + wireReq, err := getModelVersionRequestToWire(&req) if err != nil { return nil, err } @@ -358,9 +378,17 @@ func (c *internalClient) GetModelVersion(ctx context.Context, req *GetModelVersi } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/models/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } pb.literal("/versions/") - pb.singleSegment(*req.VersionArg) + if req.VersionArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.VersionArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "include_aliases", wireReq.IncludeAliases); err != nil { @@ -417,8 +445,8 @@ func (c *internalClient) GetModelVersion(ctx context.Context, req *GetModelVersi // privilege on) the registered model. For the latter case, the caller must also // be the owner or have the **USE_CATALOG** privilege on the parent catalog and // the **USE_SCHEMA** privilege on the parent schema. -func (c *internalClient) GetModelVersionByAlias(ctx context.Context, req *GetModelVersionByAliasRequest, opts ...call.Option) (*ModelVersionInfo, error) { - wireReq, err := getModelVersionByAliasRequestToWire(req) +func (c *internalClient) GetModelVersionByAlias(ctx context.Context, req GetModelVersionByAliasRequest, opts ...call.Option) (*ModelVersionInfo, error) { + wireReq, err := getModelVersionByAliasRequestToWire(&req) if err != nil { return nil, err } @@ -435,9 +463,17 @@ func (c *internalClient) GetModelVersionByAlias(ctx context.Context, req *GetMod } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/models/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } pb.literal("/aliases/") - pb.singleSegment(*req.AliasArg) + if req.AliasArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.AliasArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "include_aliases", wireReq.IncludeAliases); err != nil { @@ -491,8 +527,8 @@ func (c *internalClient) GetModelVersionByAlias(ctx context.Context, req *GetMod // privilege on) the registered model. For the latter case, the caller must also // be the owner or have the **USE_CATALOG** privilege on the parent catalog and // the **USE_SCHEMA** privilege on the parent schema. -func (c *internalClient) GetRegisteredModel(ctx context.Context, req *GetRegisteredModelRequest, opts ...call.Option) (*RegisteredModelInfo, error) { - wireReq, err := getRegisteredModelRequestToWire(req) +func (c *internalClient) GetRegisteredModel(ctx context.Context, req GetRegisteredModelRequest, opts ...call.Option) (*RegisteredModelInfo, error) { + wireReq, err := getRegisteredModelRequestToWire(&req) if err != nil { return nil, err } @@ -509,7 +545,11 @@ func (c *internalClient) GetRegisteredModel(ctx context.Context, req *GetRegiste } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/models/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "include_aliases", wireReq.IncludeAliases); err != nil { @@ -578,8 +618,8 @@ func (c *internalClient) GetRegisteredModel(ctx context.Context, req *GetRegiste // results while still providing a next_page_token. Clients must continue // reading pages until next_page_token is absent, which is the only indication // that the end of results has been reached. -func (c *internalClient) ListModelVersions(ctx context.Context, req *ListModelVersionsRequest, opts ...call.Option) (*ListModelVersionsResponse, error) { - wireReq, err := listModelVersionsRequestToWire(req) +func (c *internalClient) ListModelVersions(ctx context.Context, req ListModelVersionsRequest, opts ...call.Option) (*ListModelVersionsResponse, error) { + wireReq, err := listModelVersionsRequestToWire(&req) if err != nil { return nil, err } @@ -596,7 +636,11 @@ func (c *internalClient) ListModelVersions(ctx context.Context, req *ListModelVe } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/models/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } pb.literal("/versions") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -656,7 +700,7 @@ func (c *internalClient) ListModelVersions(ctx context.Context, req *ListModelVe // // For example: // -// for item, err := range c.ListModelVersionsIter(ctx, &ListModelVersionsRequest{}) { +// for item, err := range c.ListModelVersionsIter(ctx, ListModelVersionsRequest{}) { // if err != nil { // return err // } @@ -668,16 +712,13 @@ func (c *internalClient) ListModelVersions(ctx context.Context, req *ListModelVe // // Callers who need custom pagination logic should use // ListModelVersions directly. -func (c *internalClient) ListModelVersionsIter(ctx context.Context, req *ListModelVersionsRequest, opts ...call.Option) iter.Seq2[*ModelVersionInfo, error] { +func (c *internalClient) ListModelVersionsIter(ctx context.Context, req ListModelVersionsRequest, opts ...call.Option) iter.Seq2[*ModelVersionInfo, error] { return func(yield func(*ModelVersionInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListModelVersionsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListModelVersions(ctx, &pageReq, opts...) + resp, err := c.ListModelVersions(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -712,8 +753,8 @@ func (c *internalClient) ListModelVersionsIter(ctx context.Context, req *ListMod // results while still providing a next_page_token. Clients must continue // reading pages until next_page_token is absent, which is the only indication // that the end of results has been reached. -func (c *internalClient) ListRegisteredModels(ctx context.Context, req *ListRegisteredModelsRequest, opts ...call.Option) (*ListRegisteredModelsResponse, error) { - wireReq, err := listRegisteredModelsRequestToWire(req) +func (c *internalClient) ListRegisteredModels(ctx context.Context, req ListRegisteredModelsRequest, opts ...call.Option) (*ListRegisteredModelsResponse, error) { + wireReq, err := listRegisteredModelsRequestToWire(&req) if err != nil { return nil, err } @@ -792,7 +833,7 @@ func (c *internalClient) ListRegisteredModels(ctx context.Context, req *ListRegi // // For example: // -// for item, err := range c.ListRegisteredModelsIter(ctx, &ListRegisteredModelsRequest{}) { +// for item, err := range c.ListRegisteredModelsIter(ctx, ListRegisteredModelsRequest{}) { // if err != nil { // return err // } @@ -804,16 +845,13 @@ func (c *internalClient) ListRegisteredModels(ctx context.Context, req *ListRegi // // Callers who need custom pagination logic should use // ListRegisteredModels directly. -func (c *internalClient) ListRegisteredModelsIter(ctx context.Context, req *ListRegisteredModelsRequest, opts ...call.Option) iter.Seq2[*RegisteredModelInfo, error] { +func (c *internalClient) ListRegisteredModelsIter(ctx context.Context, req ListRegisteredModelsRequest, opts ...call.Option) iter.Seq2[*RegisteredModelInfo, error] { return func(yield func(*RegisteredModelInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListRegisteredModelsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListRegisteredModels(ctx, &pageReq, opts...) + resp, err := c.ListRegisteredModels(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -837,8 +875,8 @@ func (c *internalClient) ListRegisteredModelsIter(ctx context.Context, req *List // the latter case, the caller must also be the owner or have the // **USE_CATALOG** privilege on the parent catalog and the **USE_SCHEMA** // privilege on the parent schema. -func (c *internalClient) SetRegisteredModelAlias(ctx context.Context, req *SetRegisteredModelAliasRequest, opts ...call.Option) (*RegisteredModelAliasInfo, error) { - wireReq, err := setRegisteredModelAliasRequestToWire(req) +func (c *internalClient) SetRegisteredModelAlias(ctx context.Context, req SetRegisteredModelAliasRequest, opts ...call.Option) (*RegisteredModelAliasInfo, error) { + wireReq, err := setRegisteredModelAliasRequestToWire(&req) if err != nil { return nil, err } @@ -859,9 +897,17 @@ func (c *internalClient) SetRegisteredModelAlias(ctx context.Context, req *SetRe } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/models/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } pb.literal("/aliases/") - pb.singleSegment(*req.AliasArg) + if req.AliasArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.AliasArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -915,8 +961,8 @@ func (c *internalClient) SetRegisteredModelAlias(ctx context.Context, req *SetRe // privilege on the parent schema. // // Currently only the comment of the model version can be updated. -func (c *internalClient) UpdateModelVersion(ctx context.Context, req *UpdateModelVersionRequest, opts ...call.Option) (*ModelVersionInfo, error) { - wireReq, err := updateModelVersionRequestToWire(req) +func (c *internalClient) UpdateModelVersion(ctx context.Context, req UpdateModelVersionRequest, opts ...call.Option) (*ModelVersionInfo, error) { + wireReq, err := updateModelVersionRequestToWire(&req) if err != nil { return nil, err } @@ -937,9 +983,17 @@ func (c *internalClient) UpdateModelVersion(ctx context.Context, req *UpdateMode } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/models/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } pb.literal("/versions/") - pb.singleSegment(*req.VersionArg) + if req.VersionArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.VersionArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -994,8 +1048,8 @@ func (c *internalClient) UpdateModelVersion(ctx context.Context, req *UpdateMode // // Currently only the name, the owner or the comment of the registered model can // be updated. -func (c *internalClient) UpdateRegisteredModel(ctx context.Context, req *UpdateRegisteredModelRequest, opts ...call.Option) (*RegisteredModelInfo, error) { - wireReq, err := updateRegisteredModelRequestToWire(req) +func (c *internalClient) UpdateRegisteredModel(ctx context.Context, req UpdateRegisteredModelRequest, opts ...call.Option) (*RegisteredModelInfo, error) { + wireReq, err := updateRegisteredModelRequestToWire(&req) if err != nil { return nil, err } @@ -1016,7 +1070,11 @@ func (c *internalClient) UpdateRegisteredModel(ctx context.Context, req *UpdateR } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/models/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/uc/registeredmodels/v1/genhelper.go b/uc/registeredmodels/v1/genhelper.go old mode 100755 new mode 100644 index 3677467..3566766 --- a/uc/registeredmodels/v1/genhelper.go +++ b/uc/registeredmodels/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/registeredmodels/v1/wire.go b/uc/registeredmodels/v1/wire.go old mode 100755 new mode 100644 index 09bf1d7..4a47fd1 --- a/uc/registeredmodels/v1/wire.go +++ b/uc/registeredmodels/v1/wire.go @@ -3,9 +3,55 @@ package registeredmodels import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type connectionDependencyWire struct { ConnectionName *string `json:"connection_name,omitempty"` } @@ -37,9 +83,9 @@ type createRegisteredModelRequestWire struct { StorageLocation *string `json:"storage_location,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` FullName *string `json:"full_name,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` Aliases []registeredModelAliasInfoWire `json:"aliases,omitempty"` BrowseOnly *bool `json:"browse_only,omitempty"` @@ -49,6 +95,14 @@ func createRegisteredModelRequestToWire(v *CreateRegisteredModelRequest) (*creat if v == nil { return nil, nil } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateRegisteredModelRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateRegisteredModelRequest.UpdatedAt", err) + } aliasesWireValue, err := convertSlice(v.Aliases, registeredModelAliasInfoToWire) if err != nil { return nil, fmt.Errorf("%s: %w", "CreateRegisteredModelRequest.Aliases", err) @@ -62,9 +116,9 @@ func createRegisteredModelRequestToWire(v *CreateRegisteredModelRequest) (*creat StorageLocation: v.StorageLocation, MetastoreId: v.MetastoreId, FullName: v.FullName, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, Aliases: aliasesWireValue, BrowseOnly: v.BrowseOnly, @@ -275,19 +329,23 @@ func getModelVersionByAliasRequestToWire(v *GetModelVersionByAliasRequest) (*get } type getModelVersionRequestWire struct { - FullNameArg *string `json:"full_name_arg,omitempty"` - VersionArg *int64 `json:"version_arg,omitempty"` - IncludeAliases *bool `json:"include_aliases,omitempty"` - IncludeBrowse *bool `json:"include_browse,omitempty"` + FullNameArg *string `json:"full_name_arg,omitempty"` + VersionArg *wireInt64 `json:"version_arg,omitempty"` + IncludeAliases *bool `json:"include_aliases,omitempty"` + IncludeBrowse *bool `json:"include_browse,omitempty"` } func getModelVersionRequestToWire(v *GetModelVersionRequest) (*getModelVersionRequestWire, error) { if v == nil { return nil, nil } + versionArgWireValue, err := int64ToWire(v.VersionArg) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetModelVersionRequest.VersionArg", err) + } return &getModelVersionRequestWire{ FullNameArg: v.FullNameArg, - VersionArg: v.VersionArg, + VersionArg: versionArgWireValue, IncludeAliases: v.IncludeAliases, IncludeBrowse: v.IncludeBrowse, }, nil @@ -311,19 +369,23 @@ func getRegisteredModelRequestToWire(v *GetRegisteredModelRequest) (*getRegister } type listModelVersionsRequestWire struct { - FullNameArg *string `json:"full_name_arg,omitempty"` - MaxResults *int64 `json:"max_results,omitempty"` - PageToken *string `json:"page_token,omitempty"` - IncludeBrowse *bool `json:"include_browse,omitempty"` + FullNameArg *string `json:"full_name_arg,omitempty"` + MaxResults *wireInt64 `json:"max_results,omitempty"` + PageToken *string `json:"page_token,omitempty"` + IncludeBrowse *bool `json:"include_browse,omitempty"` } func listModelVersionsRequestToWire(v *ListModelVersionsRequest) (*listModelVersionsRequestWire, error) { if v == nil { return nil, nil } + maxResultsWireValue, err := int64ToWire(v.MaxResults) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListModelVersionsRequest.MaxResults", err) + } return &listModelVersionsRequestWire{ FullNameArg: v.FullNameArg, - MaxResults: v.MaxResults, + MaxResults: maxResultsWireValue, PageToken: v.PageToken, IncludeBrowse: v.IncludeBrowse, }, nil @@ -349,22 +411,26 @@ func listModelVersionsResponseFromWire(w *listModelVersionsResponseWire) (*ListM } type listRegisteredModelsRequestWire struct { - CatalogName *string `json:"catalog_name,omitempty"` - SchemaName *string `json:"schema_name,omitempty"` - IncludeBrowse *bool `json:"include_browse,omitempty"` - MaxResults *int64 `json:"max_results,omitempty"` - PageToken *string `json:"page_token,omitempty"` + CatalogName *string `json:"catalog_name,omitempty"` + SchemaName *string `json:"schema_name,omitempty"` + IncludeBrowse *bool `json:"include_browse,omitempty"` + MaxResults *wireInt64 `json:"max_results,omitempty"` + PageToken *string `json:"page_token,omitempty"` } func listRegisteredModelsRequestToWire(v *ListRegisteredModelsRequest) (*listRegisteredModelsRequestWire, error) { if v == nil { return nil, nil } + maxResultsWireValue, err := int64ToWire(v.MaxResults) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListRegisteredModelsRequest.MaxResults", err) + } return &listRegisteredModelsRequestWire{ CatalogName: v.CatalogName, SchemaName: v.SchemaName, IncludeBrowse: v.IncludeBrowse, - MaxResults: v.MaxResults, + MaxResults: maxResultsWireValue, PageToken: v.PageToken, }, nil } @@ -395,15 +461,15 @@ type modelVersionInfoWire struct { Source *string `json:"source,omitempty"` Comment *string `json:"comment,omitempty"` RunId *string `json:"run_id,omitempty"` - RunWorkspaceId *int64 `json:"run_workspace_id,omitempty"` + RunWorkspaceId *wireInt64 `json:"run_workspace_id,omitempty"` ModelVersionDependencies *dependencyListWire `json:"model_version_dependencies,omitempty"` Status ModelVersionStatus `json:"status,omitempty"` - Version *int64 `json:"version,omitempty"` + Version *wireInt64 `json:"version,omitempty"` StorageLocation *string `json:"storage_location,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` Id *string `json:"id,omitempty"` Aliases []registeredModelAliasInfoWire `json:"aliases,omitempty"` @@ -413,10 +479,26 @@ func modelVersionInfoFromWire(w *modelVersionInfoWire) (*ModelVersionInfo, error if w == nil { return nil, nil } + runWorkspaceIdPublicValue, err := int64FromWire(w.RunWorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ModelVersionInfo.RunWorkspaceId", err) + } modelVersionDependenciesPublicValue, err := dependencyListFromWire(w.ModelVersionDependencies) if err != nil { return nil, fmt.Errorf("%s: %w", "ModelVersionInfo.ModelVersionDependencies", err) } + versionPublicValue, err := int64FromWire(w.Version) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ModelVersionInfo.Version", err) + } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ModelVersionInfo.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ModelVersionInfo.UpdatedAt", err) + } aliasesPublicValue, err := convertSlice(w.Aliases, registeredModelAliasInfoFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "ModelVersionInfo.Aliases", err) @@ -428,15 +510,15 @@ func modelVersionInfoFromWire(w *modelVersionInfoWire) (*ModelVersionInfo, error Source: w.Source, Comment: w.Comment, RunId: w.RunId, - RunWorkspaceId: w.RunWorkspaceId, + RunWorkspaceId: runWorkspaceIdPublicValue, ModelVersionDependencies: modelVersionDependenciesPublicValue, Status: w.Status, - Version: w.Version, + Version: versionPublicValue, StorageLocation: w.StorageLocation, MetastoreId: w.MetastoreId, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, Id: w.Id, Aliases: aliasesPublicValue, @@ -444,21 +526,25 @@ func modelVersionInfoFromWire(w *modelVersionInfoWire) (*ModelVersionInfo, error } type registeredModelAliasInfoWire struct { - AliasName *string `json:"alias_name,omitempty"` - VersionNum *int64 `json:"version_num,omitempty"` - Id *string `json:"id,omitempty"` - ModelName *string `json:"model_name,omitempty"` - CatalogName *string `json:"catalog_name,omitempty"` - SchemaName *string `json:"schema_name,omitempty"` + AliasName *string `json:"alias_name,omitempty"` + VersionNum *wireInt64 `json:"version_num,omitempty"` + Id *string `json:"id,omitempty"` + ModelName *string `json:"model_name,omitempty"` + CatalogName *string `json:"catalog_name,omitempty"` + SchemaName *string `json:"schema_name,omitempty"` } func registeredModelAliasInfoToWire(v *RegisteredModelAliasInfo) (*registeredModelAliasInfoWire, error) { if v == nil { return nil, nil } + versionNumWireValue, err := int64ToWire(v.VersionNum) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RegisteredModelAliasInfo.VersionNum", err) + } return ®isteredModelAliasInfoWire{ AliasName: v.AliasName, - VersionNum: v.VersionNum, + VersionNum: versionNumWireValue, Id: v.Id, ModelName: v.ModelName, CatalogName: v.CatalogName, @@ -470,9 +556,13 @@ func registeredModelAliasInfoFromWire(w *registeredModelAliasInfoWire) (*Registe if w == nil { return nil, nil } + versionNumPublicValue, err := int64FromWire(w.VersionNum) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RegisteredModelAliasInfo.VersionNum", err) + } return &RegisteredModelAliasInfo{ AliasName: w.AliasName, - VersionNum: w.VersionNum, + VersionNum: versionNumPublicValue, Id: w.Id, ModelName: w.ModelName, CatalogName: w.CatalogName, @@ -489,9 +579,9 @@ type registeredModelInfoWire struct { StorageLocation *string `json:"storage_location,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` FullName *string `json:"full_name,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` Aliases []registeredModelAliasInfoWire `json:"aliases,omitempty"` BrowseOnly *bool `json:"browse_only,omitempty"` @@ -501,6 +591,14 @@ func registeredModelInfoFromWire(w *registeredModelInfoWire) (*RegisteredModelIn if w == nil { return nil, nil } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RegisteredModelInfo.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "RegisteredModelInfo.UpdatedAt", err) + } aliasesPublicValue, err := convertSlice(w.Aliases, registeredModelAliasInfoFromWire) if err != nil { return nil, fmt.Errorf("%s: %w", "RegisteredModelInfo.Aliases", err) @@ -514,9 +612,9 @@ func registeredModelInfoFromWire(w *registeredModelInfoWire) (*RegisteredModelIn StorageLocation: w.StorageLocation, MetastoreId: w.MetastoreId, FullName: w.FullName, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, Aliases: aliasesPublicValue, BrowseOnly: w.BrowseOnly, @@ -524,19 +622,23 @@ func registeredModelInfoFromWire(w *registeredModelInfoWire) (*RegisteredModelIn } type setRegisteredModelAliasRequestWire struct { - FullNameArg *string `json:"full_name_arg,omitempty"` - AliasArg *string `json:"alias_arg,omitempty"` - VersionNum *int64 `json:"version_num,omitempty"` + FullNameArg *string `json:"full_name_arg,omitempty"` + AliasArg *string `json:"alias_arg,omitempty"` + VersionNum *wireInt64 `json:"version_num,omitempty"` } func setRegisteredModelAliasRequestToWire(v *SetRegisteredModelAliasRequest) (*setRegisteredModelAliasRequestWire, error) { if v == nil { return nil, nil } + versionNumWireValue, err := int64ToWire(v.VersionNum) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SetRegisteredModelAliasRequest.VersionNum", err) + } return &setRegisteredModelAliasRequestWire{ FullNameArg: v.FullNameArg, AliasArg: v.AliasArg, - VersionNum: v.VersionNum, + VersionNum: versionNumWireValue, }, nil } @@ -564,22 +666,22 @@ func tableDependencyFromWire(w *tableDependencyWire) (*TableDependency, error) { type updateModelVersionRequestWire struct { FullNameArg *string `json:"full_name_arg,omitempty"` - VersionArg *int64 `json:"version_arg,omitempty"` + VersionArg *wireInt64 `json:"version_arg,omitempty"` ModelName *string `json:"model_name,omitempty"` CatalogName *string `json:"catalog_name,omitempty"` SchemaName *string `json:"schema_name,omitempty"` Source *string `json:"source,omitempty"` Comment *string `json:"comment,omitempty"` RunId *string `json:"run_id,omitempty"` - RunWorkspaceId *int64 `json:"run_workspace_id,omitempty"` + RunWorkspaceId *wireInt64 `json:"run_workspace_id,omitempty"` ModelVersionDependencies *dependencyListWire `json:"model_version_dependencies,omitempty"` Status ModelVersionStatus `json:"status,omitempty"` - Version *int64 `json:"version,omitempty"` + Version *wireInt64 `json:"version,omitempty"` StorageLocation *string `json:"storage_location,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` Id *string `json:"id,omitempty"` Aliases []registeredModelAliasInfoWire `json:"aliases,omitempty"` @@ -589,32 +691,52 @@ func updateModelVersionRequestToWire(v *UpdateModelVersionRequest) (*updateModel if v == nil { return nil, nil } + versionArgWireValue, err := int64ToWire(v.VersionArg) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateModelVersionRequest.VersionArg", err) + } + runWorkspaceIdWireValue, err := int64ToWire(v.RunWorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateModelVersionRequest.RunWorkspaceId", err) + } modelVersionDependenciesWireValue, err := dependencyListToWire(v.ModelVersionDependencies) if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateModelVersionRequest.ModelVersionDependencies", err) } + versionWireValue, err := int64ToWire(v.Version) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateModelVersionRequest.Version", err) + } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateModelVersionRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateModelVersionRequest.UpdatedAt", err) + } aliasesWireValue, err := convertSlice(v.Aliases, registeredModelAliasInfoToWire) if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateModelVersionRequest.Aliases", err) } return &updateModelVersionRequestWire{ FullNameArg: v.FullNameArg, - VersionArg: v.VersionArg, + VersionArg: versionArgWireValue, ModelName: v.ModelName, CatalogName: v.CatalogName, SchemaName: v.SchemaName, Source: v.Source, Comment: v.Comment, RunId: v.RunId, - RunWorkspaceId: v.RunWorkspaceId, + RunWorkspaceId: runWorkspaceIdWireValue, ModelVersionDependencies: modelVersionDependenciesWireValue, Status: v.Status, - Version: v.Version, + Version: versionWireValue, StorageLocation: v.StorageLocation, MetastoreId: v.MetastoreId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, Id: v.Id, Aliases: aliasesWireValue, @@ -632,9 +754,9 @@ type updateRegisteredModelRequestWire struct { StorageLocation *string `json:"storage_location,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` FullName *string `json:"full_name,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` Aliases []registeredModelAliasInfoWire `json:"aliases,omitempty"` BrowseOnly *bool `json:"browse_only,omitempty"` @@ -644,6 +766,14 @@ func updateRegisteredModelRequestToWire(v *UpdateRegisteredModelRequest) (*updat if v == nil { return nil, nil } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateRegisteredModelRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateRegisteredModelRequest.UpdatedAt", err) + } aliasesWireValue, err := convertSlice(v.Aliases, registeredModelAliasInfoToWire) if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateRegisteredModelRequest.Aliases", err) @@ -659,9 +789,9 @@ func updateRegisteredModelRequestToWire(v *UpdateRegisteredModelRequest) (*updat StorageLocation: v.StorageLocation, MetastoreId: v.MetastoreId, FullName: v.FullName, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, Aliases: aliasesWireValue, BrowseOnly: v.BrowseOnly, diff --git a/uc/resourcequotas/CHANGELOG.md b/uc/resourcequotas/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/resourcequotas/CHANGELOG.md +++ b/uc/resourcequotas/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/resourcequotas/go.mod b/uc/resourcequotas/go.mod index 57cc643..89c32c9 100644 --- a/uc/resourcequotas/go.mod +++ b/uc/resourcequotas/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/resourcequotas/internal/version.go b/uc/resourcequotas/internal/version.go index 3e2c4da..fddf176 100644 --- a/uc/resourcequotas/internal/version.go +++ b/uc/resourcequotas/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-resourcequotas" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/resourcequotas/v1/client.go b/uc/resourcequotas/v1/client.go old mode 100755 new mode 100644 index bd7b2be..122624c --- a/uc/resourcequotas/v1/client.go +++ b/uc/resourcequotas/v1/client.go @@ -77,7 +77,7 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // defined as a child-parent pair. This API also refreshes the quota count if it // is out of date. Refreshes are triggered asynchronously. The updated count // might not be returned in the first call. -func (c *internalClient) GetQuota(ctx context.Context, req *GetQuotaRequest, opts ...call.Option) (*GetQuotaResponse, error) { +func (c *internalClient) GetQuota(ctx context.Context, req GetQuotaRequest, opts ...call.Option) (*GetQuotaResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -91,11 +91,23 @@ func (c *internalClient) GetQuota(ctx context.Context, req *GetQuotaRequest, opt } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/resource-quotas/") - pb.singleSegment(*req.ParentSecurableType) + if req.ParentSecurableType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ParentSecurableType) + } pb.literal("/") - pb.singleSegment(*req.ParentFullName) + if req.ParentFullName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.ParentFullName) + } pb.literal("/") - pb.singleSegment(*req.QuotaName) + if req.QuotaName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.QuotaName) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -148,8 +160,8 @@ func (c *internalClient) GetQuota(ctx context.Context, req *GetQuotaRequest, opt // results while still providing a next_page_token. Clients must continue // reading pages until next_page_token is absent, which is the only indication // that the end of results has been reached. -func (c *internalClient) ListQuotas(ctx context.Context, req *ListQuotasRequest, opts ...call.Option) (*ListQuotasResponse, error) { - wireReq, err := listQuotasRequestToWire(req) +func (c *internalClient) ListQuotas(ctx context.Context, req ListQuotasRequest, opts ...call.Option) (*ListQuotasResponse, error) { + wireReq, err := listQuotasRequestToWire(&req) if err != nil { return nil, err } @@ -219,7 +231,7 @@ func (c *internalClient) ListQuotas(ctx context.Context, req *ListQuotasRequest, // // For example: // -// for item, err := range c.ListQuotasIter(ctx, &ListQuotasRequest{}) { +// for item, err := range c.ListQuotasIter(ctx, ListQuotasRequest{}) { // if err != nil { // return err // } @@ -231,16 +243,13 @@ func (c *internalClient) ListQuotas(ctx context.Context, req *ListQuotasRequest, // // Callers who need custom pagination logic should use // ListQuotas directly. -func (c *internalClient) ListQuotasIter(ctx context.Context, req *ListQuotasRequest, opts ...call.Option) iter.Seq2[*QuotaInfo, error] { +func (c *internalClient) ListQuotasIter(ctx context.Context, req ListQuotasRequest, opts ...call.Option) iter.Seq2[*QuotaInfo, error] { return func(yield func(*QuotaInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListQuotasRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListQuotas(ctx, &pageReq, opts...) + resp, err := c.ListQuotas(ctx, pageReq, opts...) if err != nil { yield(nil, err) return diff --git a/uc/resourcequotas/v1/genhelper.go b/uc/resourcequotas/v1/genhelper.go old mode 100755 new mode 100644 index 45b9b91..9a04c0a --- a/uc/resourcequotas/v1/genhelper.go +++ b/uc/resourcequotas/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/resourcequotas/v1/model.go b/uc/resourcequotas/v1/model.go old mode 100755 new mode 100644 index 4b06ec2..09333a4 --- a/uc/resourcequotas/v1/model.go +++ b/uc/resourcequotas/v1/model.go @@ -24,7 +24,11 @@ const ( SecurableType_Credential SecurableType = "CREDENTIAL" SecurableType_ExternalMetadata SecurableType = "EXTERNAL_METADATA" // TODO: [UC-2980] Staging tables aren't full-fleged securables yet. - SecurableType_StagingTable SecurableType = "STAGING_TABLE" + SecurableType_StagingTable SecurableType = "STAGING_TABLE" + SecurableType_Model SecurableType = "MODEL" + SecurableType_ModelService SecurableType = "MODEL_SERVICE" + SecurableType_McpService SecurableType = "MCP_SERVICE" + SecurableType_ModelProviderService SecurableType = "MODEL_PROVIDER_SERVICE" ) type GetQuotaRequest struct { diff --git a/uc/resourcequotas/v1/wire.go b/uc/resourcequotas/v1/wire.go old mode 100755 new mode 100644 index aa20ccb..f2e7ebf --- a/uc/resourcequotas/v1/wire.go +++ b/uc/resourcequotas/v1/wire.go @@ -3,9 +3,55 @@ package resourcequotas import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type getQuotaResponseWire struct { QuotaInfo *quotaInfoWire `json:"quota_info,omitempty"` } @@ -63,20 +109,24 @@ type quotaInfoWire struct { QuotaName *string `json:"quota_name,omitempty"` QuotaCount *int `json:"quota_count,omitempty"` QuotaLimit *int `json:"quota_limit,omitempty"` - LastRefreshedAt *int64 `json:"last_refreshed_at,omitempty"` + LastRefreshedAt *wireInt64 `json:"last_refreshed_at,omitempty"` } func quotaInfoFromWire(w *quotaInfoWire) (*QuotaInfo, error) { if w == nil { return nil, nil } + lastRefreshedAtPublicValue, err := int64FromWire(w.LastRefreshedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "QuotaInfo.LastRefreshedAt", err) + } return &QuotaInfo{ ParentSecurableType: w.ParentSecurableType, ParentFullName: w.ParentFullName, QuotaName: w.QuotaName, QuotaCount: w.QuotaCount, QuotaLimit: w.QuotaLimit, - LastRefreshedAt: w.LastRefreshedAt, + LastRefreshedAt: lastRefreshedAtPublicValue, }, nil } diff --git a/uc/rfa/CHANGELOG.md b/uc/rfa/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/rfa/CHANGELOG.md +++ b/uc/rfa/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/rfa/go.mod b/uc/rfa/go.mod index dbc5fd2..a7280c9 100644 --- a/uc/rfa/go.mod +++ b/uc/rfa/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/rfa/internal/version.go b/uc/rfa/internal/version.go index a85413d..8aa4df8 100644 --- a/uc/rfa/internal/version.go +++ b/uc/rfa/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-rfa" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/rfa/v1/client.go b/uc/rfa/v1/client.go old mode 100755 new mode 100644 index 358c80c..c619251 --- a/uc/rfa/v1/client.go +++ b/uc/rfa/v1/client.go @@ -82,8 +82,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // The supported securable types are: "metastore", "catalog", "schema", "table", // "external_location", "connection", "credential", "function", // "registered_model", and "volume". -func (c *internalClient) BatchCreateAccessRequests(ctx context.Context, req *BatchCreateAccessRequestsRequest, opts ...call.Option) (*BatchCreateAccessRequestsResponse, error) { - wireReq, err := batchCreateAccessRequestsRequestToWire(req) +func (c *internalClient) BatchCreateAccessRequests(ctx context.Context, req BatchCreateAccessRequestsRequest, opts ...call.Option) (*BatchCreateAccessRequestsResponse, error) { + wireReq, err := batchCreateAccessRequestsRequestToWire(&req) if err != nil { return nil, err } @@ -155,7 +155,7 @@ func (c *internalClient) BatchCreateAccessRequests(ctx context.Context, req *Bat // The supported securable types are: "metastore", "catalog", "schema", "table", // "external_location", "connection", "credential", "function", // "registered_model", and "volume". -func (c *internalClient) GetAccessRequestDestinations(ctx context.Context, req *GetAccessRequestDestinationsRequest, opts ...call.Option) (*AccessRequestDestinations, error) { +func (c *internalClient) GetAccessRequestDestinations(ctx context.Context, req GetAccessRequestDestinationsRequest, opts ...call.Option) (*AccessRequestDestinations, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -169,9 +169,17 @@ func (c *internalClient) GetAccessRequestDestinations(ctx context.Context, req * } pb := pathBuilder{} pb.literal("/api/3.0/rfa/destinations/") - pb.singleSegment(*req.SecurableType) + if req.SecurableType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SecurableType) + } pb.literal("/") - pb.singleSegment(*req.FullName) + if req.FullName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullName) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -220,15 +228,15 @@ func (c *internalClient) GetAccessRequestDestinations(ctx context.Context, req * // must be a metastore admin, the owner of the securable, or a user that has the // **MANAGE** privilege on the securable in order to assign destinations. A // maximum of 5 emails and 5 external notification destinations (Slack, -// Microsoft Teams, and Generic Webhook destinations) can be assigned to a -// securable. If a URL destination is assigned, no other destinations can be -// set. +// Microsoft Teams, Generic Webhook, and Databricks App Slack/Teams +// destinations) can be assigned to a securable. If a URL destination is +// assigned, no other destinations can be set. // // The supported securable types are: "metastore", "catalog", "schema", "table", // "external_location", "connection", "credential", "function", // "registered_model", and "volume". -func (c *internalClient) UpdateAccessRequestDestinations(ctx context.Context, req *UpdateAccessRequestDestinationsRequest, opts ...call.Option) (*AccessRequestDestinations, error) { - wireReq, err := updateAccessRequestDestinationsRequestToWire(req) +func (c *internalClient) UpdateAccessRequestDestinations(ctx context.Context, req UpdateAccessRequestDestinationsRequest, opts ...call.Option) (*AccessRequestDestinations, error) { + wireReq, err := updateAccessRequestDestinationsRequestToWire(&req) if err != nil { return nil, err } diff --git a/uc/rfa/v1/genhelper.go b/uc/rfa/v1/genhelper.go old mode 100755 new mode 100644 index a2369ff..29cebd0 --- a/uc/rfa/v1/genhelper.go +++ b/uc/rfa/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/rfa/v1/model.go b/uc/rfa/v1/model.go old mode 100755 new mode 100644 index 5d20af5..af63dff --- a/uc/rfa/v1/model.go +++ b/uc/rfa/v1/model.go @@ -48,7 +48,11 @@ const ( SecurableType_Credential SecurableType = "CREDENTIAL" SecurableType_ExternalMetadata SecurableType = "EXTERNAL_METADATA" // TODO: [UC-2980] Staging tables aren't full-fleged securables yet. - SecurableType_StagingTable SecurableType = "STAGING_TABLE" + SecurableType_StagingTable SecurableType = "STAGING_TABLE" + SecurableType_Model SecurableType = "MODEL" + SecurableType_ModelService SecurableType = "MODEL_SERVICE" + SecurableType_McpService SecurableType = "MCP_SERVICE" + SecurableType_ModelProviderService SecurableType = "MODEL_PROVIDER_SERVICE" ) type SpecialDestination string diff --git a/uc/schemas/CHANGELOG.md b/uc/schemas/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/schemas/CHANGELOG.md +++ b/uc/schemas/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/schemas/go.mod b/uc/schemas/go.mod index 030cf32..3a87e99 100644 --- a/uc/schemas/go.mod +++ b/uc/schemas/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/schemas/internal/version.go b/uc/schemas/internal/version.go index 15382de..e207233 100644 --- a/uc/schemas/internal/version.go +++ b/uc/schemas/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-schemas" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/schemas/v1/client.go b/uc/schemas/v1/client.go old mode 100755 new mode 100644 index 8783f82..cccdfb5 --- a/uc/schemas/v1/client.go +++ b/uc/schemas/v1/client.go @@ -77,8 +77,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Creates a new schema for catalog in the Metastore. The caller must be a // metastore admin, or have the **CREATE_SCHEMA** privilege in the parent // catalog. -func (c *internalClient) CreateSchema(ctx context.Context, req *CreateSchemaRequest, opts ...call.Option) (*SchemaInfo, error) { - wireReq, err := createSchemaRequestToWire(req) +func (c *internalClient) CreateSchema(ctx context.Context, req CreateSchemaRequest, opts ...call.Option) (*SchemaInfo, error) { + wireReq, err := createSchemaRequestToWire(&req) if err != nil { return nil, err } @@ -144,8 +144,8 @@ func (c *internalClient) CreateSchema(ctx context.Context, req *CreateSchemaRequ // Deletes the specified schema from the parent catalog. The caller must be the // owner of the schema or an owner of the parent catalog. -func (c *internalClient) DeleteSchema(ctx context.Context, req *DeleteSchemaRequest, opts ...call.Option) (*DeleteSchemaResponse, error) { - wireReq, err := deleteSchemaRequestToWire(req) +func (c *internalClient) DeleteSchema(ctx context.Context, req DeleteSchemaRequest, opts ...call.Option) (*DeleteSchemaResponse, error) { + wireReq, err := deleteSchemaRequestToWire(&req) if err != nil { return nil, err } @@ -162,7 +162,11 @@ func (c *internalClient) DeleteSchema(ctx context.Context, req *DeleteSchemaRequ } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/schemas/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "force", wireReq.Force); err != nil { @@ -207,8 +211,8 @@ func (c *internalClient) DeleteSchema(ctx context.Context, req *DeleteSchemaRequ // Gets the specified schema within the metastore. The caller must be a // metastore admin, the owner of the schema, or a user that has the // **USE_SCHEMA** privilege on the schema. -func (c *internalClient) GetSchema(ctx context.Context, req *GetSchemaRequest, opts ...call.Option) (*SchemaInfo, error) { - wireReq, err := getSchemaRequestToWire(req) +func (c *internalClient) GetSchema(ctx context.Context, req GetSchemaRequest, opts ...call.Option) (*SchemaInfo, error) { + wireReq, err := getSchemaRequestToWire(&req) if err != nil { return nil, err } @@ -225,7 +229,11 @@ func (c *internalClient) GetSchema(ctx context.Context, req *GetSchemaRequest, o } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/schemas/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "include_browse", wireReq.IncludeBrowse); err != nil { @@ -286,8 +294,8 @@ func (c *internalClient) GetSchema(ctx context.Context, req *GetSchemaRequest, o // contain zero results while still providing a next_page_token. Clients must // continue reading pages until next_page_token is absent, which is the only // indication that the end of results has been reached. -func (c *internalClient) ListSchemas(ctx context.Context, req *ListSchemasRequest, opts ...call.Option) (*ListSchemasResponse, error) { - wireReq, err := listSchemasRequestToWire(req) +func (c *internalClient) ListSchemas(ctx context.Context, req ListSchemasRequest, opts ...call.Option) (*ListSchemasResponse, error) { + wireReq, err := listSchemasRequestToWire(&req) if err != nil { return nil, err } @@ -363,7 +371,7 @@ func (c *internalClient) ListSchemas(ctx context.Context, req *ListSchemasReques // // For example: // -// for item, err := range c.ListSchemasIter(ctx, &ListSchemasRequest{}) { +// for item, err := range c.ListSchemasIter(ctx, ListSchemasRequest{}) { // if err != nil { // return err // } @@ -375,16 +383,13 @@ func (c *internalClient) ListSchemas(ctx context.Context, req *ListSchemasReques // // Callers who need custom pagination logic should use // ListSchemas directly. -func (c *internalClient) ListSchemasIter(ctx context.Context, req *ListSchemasRequest, opts ...call.Option) iter.Seq2[*SchemaInfo, error] { +func (c *internalClient) ListSchemasIter(ctx context.Context, req ListSchemasRequest, opts ...call.Option) iter.Seq2[*SchemaInfo, error] { return func(yield func(*SchemaInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListSchemasRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListSchemas(ctx, &pageReq, opts...) + resp, err := c.ListSchemas(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -407,8 +412,8 @@ func (c *internalClient) ListSchemasIter(ctx context.Context, req *ListSchemasRe // field can be changed in the update. If the __name__ field must be updated, // the caller must be a metastore admin or have the **CREATE_SCHEMA** privilege // on the parent catalog. -func (c *internalClient) UpdateSchema(ctx context.Context, req *UpdateSchemaRequest, opts ...call.Option) (*SchemaInfo, error) { - wireReq, err := updateSchemaRequestToWire(req) +func (c *internalClient) UpdateSchema(ctx context.Context, req UpdateSchemaRequest, opts ...call.Option) (*SchemaInfo, error) { + wireReq, err := updateSchemaRequestToWire(&req) if err != nil { return nil, err } @@ -429,7 +434,11 @@ func (c *internalClient) UpdateSchema(ctx context.Context, req *UpdateSchemaRequ } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/schemas/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/uc/schemas/v1/genhelper.go b/uc/schemas/v1/genhelper.go old mode 100755 new mode 100644 index 3d56735..65d87f0 --- a/uc/schemas/v1/genhelper.go +++ b/uc/schemas/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/schemas/v1/wire.go b/uc/schemas/v1/wire.go old mode 100755 new mode 100644 index c932a72..58cc84d --- a/uc/schemas/v1/wire.go +++ b/uc/schemas/v1/wire.go @@ -3,9 +3,55 @@ package schemas import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type createSchemaRequestWire struct { Name *string `json:"name,omitempty"` CatalogName *string `json:"catalog_name,omitempty"` @@ -15,16 +61,16 @@ type createSchemaRequestWire struct { EnablePredictiveOptimization *string `json:"enable_predictive_optimization,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` FullName *string `json:"full_name,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` CatalogType CatalogType `json:"catalog_type,omitempty"` StorageLocation *string `json:"storage_location,omitempty"` EffectivePredictiveOptimizationFlag *effectivePredictiveOptimizationFlagWire `json:"effective_predictive_optimization_flag,omitempty"` SchemaId *string `json:"schema_id,omitempty"` BrowseOnly *bool `json:"browse_only,omitempty"` - CustomMaxRetentionHours *int64 `json:"custom_max_retention_hours,omitempty"` + CustomMaxRetentionHours *wireInt64 `json:"custom_max_retention_hours,omitempty"` Properties map[string]string `json:"properties,omitempty"` Options map[string]string `json:"options,omitempty"` } @@ -33,10 +79,22 @@ func createSchemaRequestToWire(v *CreateSchemaRequest) (*createSchemaRequestWire if v == nil { return nil, nil } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateSchemaRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateSchemaRequest.UpdatedAt", err) + } effectivePredictiveOptimizationFlagWireValue, err := effectivePredictiveOptimizationFlagToWire(v.EffectivePredictiveOptimizationFlag) if err != nil { return nil, fmt.Errorf("%s: %w", "CreateSchemaRequest.EffectivePredictiveOptimizationFlag", err) } + customMaxRetentionHoursWireValue, err := int64ToWire(v.CustomMaxRetentionHours) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateSchemaRequest.CustomMaxRetentionHours", err) + } return &createSchemaRequestWire{ Name: v.Name, CatalogName: v.CatalogName, @@ -46,16 +104,16 @@ func createSchemaRequestToWire(v *CreateSchemaRequest) (*createSchemaRequestWire EnablePredictiveOptimization: v.EnablePredictiveOptimization, MetastoreId: v.MetastoreId, FullName: v.FullName, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, CatalogType: v.CatalogType, StorageLocation: v.StorageLocation, EffectivePredictiveOptimizationFlag: effectivePredictiveOptimizationFlagWireValue, SchemaId: v.SchemaId, BrowseOnly: v.BrowseOnly, - CustomMaxRetentionHours: v.CustomMaxRetentionHours, + CustomMaxRetentionHours: customMaxRetentionHoursWireValue, Properties: v.Properties, Options: v.Options, }, nil @@ -166,16 +224,16 @@ type schemaInfoWire struct { EnablePredictiveOptimization *string `json:"enable_predictive_optimization,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` FullName *string `json:"full_name,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` CatalogType CatalogType `json:"catalog_type,omitempty"` StorageLocation *string `json:"storage_location,omitempty"` EffectivePredictiveOptimizationFlag *effectivePredictiveOptimizationFlagWire `json:"effective_predictive_optimization_flag,omitempty"` SchemaId *string `json:"schema_id,omitempty"` BrowseOnly *bool `json:"browse_only,omitempty"` - CustomMaxRetentionHours *int64 `json:"custom_max_retention_hours,omitempty"` + CustomMaxRetentionHours *wireInt64 `json:"custom_max_retention_hours,omitempty"` Properties map[string]string `json:"properties,omitempty"` Options map[string]string `json:"options,omitempty"` } @@ -184,10 +242,22 @@ func schemaInfoFromWire(w *schemaInfoWire) (*SchemaInfo, error) { if w == nil { return nil, nil } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SchemaInfo.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SchemaInfo.UpdatedAt", err) + } effectivePredictiveOptimizationFlagPublicValue, err := effectivePredictiveOptimizationFlagFromWire(w.EffectivePredictiveOptimizationFlag) if err != nil { return nil, fmt.Errorf("%s: %w", "SchemaInfo.EffectivePredictiveOptimizationFlag", err) } + customMaxRetentionHoursPublicValue, err := int64FromWire(w.CustomMaxRetentionHours) + if err != nil { + return nil, fmt.Errorf("%s: %w", "SchemaInfo.CustomMaxRetentionHours", err) + } return &SchemaInfo{ Name: w.Name, CatalogName: w.CatalogName, @@ -197,16 +267,16 @@ func schemaInfoFromWire(w *schemaInfoWire) (*SchemaInfo, error) { EnablePredictiveOptimization: w.EnablePredictiveOptimization, MetastoreId: w.MetastoreId, FullName: w.FullName, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, CatalogType: w.CatalogType, StorageLocation: w.StorageLocation, EffectivePredictiveOptimizationFlag: effectivePredictiveOptimizationFlagPublicValue, SchemaId: w.SchemaId, BrowseOnly: w.BrowseOnly, - CustomMaxRetentionHours: w.CustomMaxRetentionHours, + CustomMaxRetentionHours: customMaxRetentionHoursPublicValue, Properties: w.Properties, Options: w.Options, }, nil @@ -223,16 +293,16 @@ type updateSchemaRequestWire struct { EnablePredictiveOptimization *string `json:"enable_predictive_optimization,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` FullName *string `json:"full_name,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` CatalogType CatalogType `json:"catalog_type,omitempty"` StorageLocation *string `json:"storage_location,omitempty"` EffectivePredictiveOptimizationFlag *effectivePredictiveOptimizationFlagWire `json:"effective_predictive_optimization_flag,omitempty"` SchemaId *string `json:"schema_id,omitempty"` BrowseOnly *bool `json:"browse_only,omitempty"` - CustomMaxRetentionHours *int64 `json:"custom_max_retention_hours,omitempty"` + CustomMaxRetentionHours *wireInt64 `json:"custom_max_retention_hours,omitempty"` Properties map[string]string `json:"properties,omitempty"` Options map[string]string `json:"options,omitempty"` } @@ -241,10 +311,22 @@ func updateSchemaRequestToWire(v *UpdateSchemaRequest) (*updateSchemaRequestWire if v == nil { return nil, nil } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateSchemaRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateSchemaRequest.UpdatedAt", err) + } effectivePredictiveOptimizationFlagWireValue, err := effectivePredictiveOptimizationFlagToWire(v.EffectivePredictiveOptimizationFlag) if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateSchemaRequest.EffectivePredictiveOptimizationFlag", err) } + customMaxRetentionHoursWireValue, err := int64ToWire(v.CustomMaxRetentionHours) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateSchemaRequest.CustomMaxRetentionHours", err) + } return &updateSchemaRequestWire{ FullNameArg: v.FullNameArg, NewName: v.NewName, @@ -256,16 +338,16 @@ func updateSchemaRequestToWire(v *UpdateSchemaRequest) (*updateSchemaRequestWire EnablePredictiveOptimization: v.EnablePredictiveOptimization, MetastoreId: v.MetastoreId, FullName: v.FullName, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, CatalogType: v.CatalogType, StorageLocation: v.StorageLocation, EffectivePredictiveOptimizationFlag: effectivePredictiveOptimizationFlagWireValue, SchemaId: v.SchemaId, BrowseOnly: v.BrowseOnly, - CustomMaxRetentionHours: v.CustomMaxRetentionHours, + CustomMaxRetentionHours: customMaxRetentionHoursWireValue, Properties: v.Properties, Options: v.Options, }, nil diff --git a/uc/secrets/CHANGELOG.md b/uc/secrets/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/secrets/CHANGELOG.md +++ b/uc/secrets/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/secrets/go.mod b/uc/secrets/go.mod index a3f1fd9..c9bb901 100644 --- a/uc/secrets/go.mod +++ b/uc/secrets/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/secrets/internal/version.go b/uc/secrets/internal/version.go index 0402d5e..34a42d2 100644 --- a/uc/secrets/internal/version.go +++ b/uc/secrets/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-secrets" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/secrets/v1/client.go b/uc/secrets/v1/client.go old mode 100755 new mode 100644 index 1005f05..bb71ec6 --- a/uc/secrets/v1/client.go +++ b/uc/secrets/v1/client.go @@ -82,8 +82,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // // The secret is stored in the specified catalog and schema, and the **value** // field contains the sensitive data to be securely stored. -func (c *internalClient) CreateSecret(ctx context.Context, req *CreateSecretRequest, opts ...call.Option) (*Secret, error) { - wireReq, err := createSecretRequestToWire(req) +func (c *internalClient) CreateSecret(ctx context.Context, req CreateSecretRequest, opts ...call.Option) (*Secret, error) { + wireReq, err := createSecretRequestToWire(&req) if err != nil { return nil, err } @@ -150,7 +150,7 @@ func (c *internalClient) CreateSecret(ctx context.Context, req *CreateSecretRequ // Deletes a secret by its three-level (fully qualified) name. // // You must be the owner of the secret or a metastore admin. -func (c *internalClient) DeleteSecret(ctx context.Context, req *DeleteSecretRequest, opts ...call.Option) error { +func (c *internalClient) DeleteSecret(ctx context.Context, req DeleteSecretRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -164,7 +164,11 @@ func (c *internalClient) DeleteSecret(ctx context.Context, req *DeleteSecretRequ } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/secrets/") - pb.singleSegment(*req.FullName) + if req.FullName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullName) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -208,8 +212,8 @@ func (c *internalClient) DeleteSecret(ctx context.Context, req *DeleteSecretRequ // The secret value isn't returned by default. To retrieve it, you must also // have the **READ_SECRET** privilege and set **include_value** to true in the // request. -func (c *internalClient) GetSecret(ctx context.Context, req *GetSecretRequest, opts ...call.Option) (*Secret, error) { - wireReq, err := getSecretRequestToWire(req) +func (c *internalClient) GetSecret(ctx context.Context, req GetSecretRequest, opts ...call.Option) (*Secret, error) { + wireReq, err := getSecretRequestToWire(&req) if err != nil { return nil, err } @@ -226,7 +230,11 @@ func (c *internalClient) GetSecret(ctx context.Context, req *GetSecretRequest, o } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/secrets/") - pb.singleSegment(*req.FullName) + if req.FullName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullName) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "include_value", wireReq.IncludeValue); err != nil { @@ -282,8 +290,8 @@ func (c *internalClient) GetSecret(ctx context.Context, req *GetSecretRequest, o // Both **catalog_name** and **schema_name** must be specified together to // filter secrets within a specific schema. Results are paginated; use the // **page_token** field from the response to retrieve subsequent pages. -func (c *internalClient) ListSecrets(ctx context.Context, req *ListSecretsRequest, opts ...call.Option) (*ListSecretsResponse, error) { - wireReq, err := listSecretsRequestToWire(req) +func (c *internalClient) ListSecrets(ctx context.Context, req ListSecretsRequest, opts ...call.Option) (*ListSecretsResponse, error) { + wireReq, err := listSecretsRequestToWire(&req) if err != nil { return nil, err } @@ -359,7 +367,7 @@ func (c *internalClient) ListSecrets(ctx context.Context, req *ListSecretsReques // // For example: // -// for item, err := range c.ListSecretsIter(ctx, &ListSecretsRequest{}) { +// for item, err := range c.ListSecretsIter(ctx, ListSecretsRequest{}) { // if err != nil { // return err // } @@ -371,16 +379,13 @@ func (c *internalClient) ListSecrets(ctx context.Context, req *ListSecretsReques // // Callers who need custom pagination logic should use // ListSecrets directly. -func (c *internalClient) ListSecretsIter(ctx context.Context, req *ListSecretsRequest, opts ...call.Option) iter.Seq2[*Secret, error] { +func (c *internalClient) ListSecretsIter(ctx context.Context, req ListSecretsRequest, opts ...call.Option) iter.Seq2[*Secret, error] { return func(yield func(*Secret, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListSecretsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListSecrets(ctx, &pageReq, opts...) + resp, err := c.ListSecrets(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -406,8 +411,8 @@ func (c *internalClient) ListSecretsIter(ctx context.Context, req *ListSecretsRe // Use the **update_mask** field to specify which fields to update. Supported // updatable fields include **value**, **comment**, **owner**, and // **expire_time**. -func (c *internalClient) UpdateSecret(ctx context.Context, req *UpdateSecretRequest, opts ...call.Option) (*Secret, error) { - wireReq, err := updateSecretRequestToWire(req) +func (c *internalClient) UpdateSecret(ctx context.Context, req UpdateSecretRequest, opts ...call.Option) (*Secret, error) { + wireReq, err := updateSecretRequestToWire(&req) if err != nil { return nil, err } @@ -428,7 +433,11 @@ func (c *internalClient) UpdateSecret(ctx context.Context, req *UpdateSecretRequ } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/secrets/") - pb.singleSegment(*req.FullName) + if req.FullName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullName) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { diff --git a/uc/secrets/v1/genhelper.go b/uc/secrets/v1/genhelper.go old mode 100755 new mode 100644 index 81cbef7..1066524 --- a/uc/secrets/v1/genhelper.go +++ b/uc/secrets/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/systemschemas/CHANGELOG.md b/uc/systemschemas/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/systemschemas/CHANGELOG.md +++ b/uc/systemschemas/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/systemschemas/go.mod b/uc/systemschemas/go.mod index 7cd6423..3dfaf79 100644 --- a/uc/systemschemas/go.mod +++ b/uc/systemschemas/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/systemschemas/internal/version.go b/uc/systemschemas/internal/version.go index b91a1e8..07e0d9d 100644 --- a/uc/systemschemas/internal/version.go +++ b/uc/systemschemas/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-systemschemas" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/systemschemas/v1/client.go b/uc/systemschemas/v1/client.go old mode 100755 new mode 100644 index a28d30f..ced0aa1 --- a/uc/systemschemas/v1/client.go +++ b/uc/systemschemas/v1/client.go @@ -76,7 +76,7 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Disables the system schema and removes it from the system catalog. The caller // must be an account admin or a metastore admin. -func (c *internalClient) DisableSystemSchema(ctx context.Context, req *DisableSystemSchemaRequest, opts ...call.Option) (*DisableSystemSchemaResponse, error) { +func (c *internalClient) DisableSystemSchema(ctx context.Context, req DisableSystemSchemaRequest, opts ...call.Option) (*DisableSystemSchemaResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -90,9 +90,17 @@ func (c *internalClient) DisableSystemSchema(ctx context.Context, req *DisableSy } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/metastores/") - pb.singleSegment(*req.MetastoreId) + if req.MetastoreId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MetastoreId) + } pb.literal("/systemschemas/") - pb.singleSegment(*req.Schema) + if req.Schema == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Schema) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -133,8 +141,8 @@ func (c *internalClient) DisableSystemSchema(ctx context.Context, req *DisableSy // Enables the system schema and adds it to the system catalog. The caller must // be an account admin or a metastore admin. -func (c *internalClient) EnableSystemSchema(ctx context.Context, req *EnableSystemSchemaRequest, opts ...call.Option) (*EnableSystemSchemaResponse, error) { - wireReq, err := enableSystemSchemaRequestToWire(req) +func (c *internalClient) EnableSystemSchema(ctx context.Context, req EnableSystemSchemaRequest, opts ...call.Option) (*EnableSystemSchemaResponse, error) { + wireReq, err := enableSystemSchemaRequestToWire(&req) if err != nil { return nil, err } @@ -155,9 +163,17 @@ func (c *internalClient) EnableSystemSchema(ctx context.Context, req *EnableSyst } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/metastores/") - pb.singleSegment(*req.MetastoreId) + if req.MetastoreId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MetastoreId) + } pb.literal("/systemschemas/") - pb.singleSegment(*req.Schema) + if req.Schema == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Schema) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -207,8 +223,8 @@ func (c *internalClient) EnableSystemSchema(ctx context.Context, req *EnableSyst // contain zero results while still providing a next_page_token. Clients must // continue reading pages until next_page_token is absent, which is the only // indication that the end of results has been reached. -func (c *internalClient) ListSystemSchemas(ctx context.Context, req *ListSystemSchemasRequest, opts ...call.Option) (*ListSystemSchemasResponse, error) { - wireReq, err := listSystemSchemasRequestToWire(req) +func (c *internalClient) ListSystemSchemas(ctx context.Context, req ListSystemSchemasRequest, opts ...call.Option) (*ListSystemSchemasResponse, error) { + wireReq, err := listSystemSchemasRequestToWire(&req) if err != nil { return nil, err } @@ -225,7 +241,11 @@ func (c *internalClient) ListSystemSchemas(ctx context.Context, req *ListSystemS } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/metastores/") - pb.singleSegment(*req.MetastoreId) + if req.MetastoreId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.MetastoreId) + } pb.literal("/systemschemas") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -282,7 +302,7 @@ func (c *internalClient) ListSystemSchemas(ctx context.Context, req *ListSystemS // // For example: // -// for item, err := range c.ListSystemSchemasIter(ctx, &ListSystemSchemasRequest{}) { +// for item, err := range c.ListSystemSchemasIter(ctx, ListSystemSchemasRequest{}) { // if err != nil { // return err // } @@ -294,16 +314,13 @@ func (c *internalClient) ListSystemSchemas(ctx context.Context, req *ListSystemS // // Callers who need custom pagination logic should use // ListSystemSchemas directly. -func (c *internalClient) ListSystemSchemasIter(ctx context.Context, req *ListSystemSchemasRequest, opts ...call.Option) iter.Seq2[*SystemSchemaInfo, error] { +func (c *internalClient) ListSystemSchemasIter(ctx context.Context, req ListSystemSchemasRequest, opts ...call.Option) iter.Seq2[*SystemSchemaInfo, error] { return func(yield func(*SystemSchemaInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListSystemSchemasRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListSystemSchemas(ctx, &pageReq, opts...) + resp, err := c.ListSystemSchemas(ctx, pageReq, opts...) if err != nil { yield(nil, err) return diff --git a/uc/systemschemas/v1/genhelper.go b/uc/systemschemas/v1/genhelper.go old mode 100755 new mode 100644 index 51cb642..b73eb73 --- a/uc/systemschemas/v1/genhelper.go +++ b/uc/systemschemas/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/tables/CHANGELOG.md b/uc/tables/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/tables/CHANGELOG.md +++ b/uc/tables/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/tables/go.mod b/uc/tables/go.mod index 52046c2..979e02f 100644 --- a/uc/tables/go.mod +++ b/uc/tables/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/tables/internal/version.go b/uc/tables/internal/version.go index ee201a3..a8f0adc 100644 --- a/uc/tables/internal/version.go +++ b/uc/tables/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-tables" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/tables/v1/client.go b/uc/tables/v1/client.go old mode 100755 new mode 100644 index ee9925f..8672e83 --- a/uc/tables/v1/client.go +++ b/uc/tables/v1/client.go @@ -98,8 +98,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // only **table_type** **EXTERNAL** and **data_source_format** **DELTA** are // supported. Additionally, column masks are not supported when creating tables // through this API. -func (c *internalClient) CreateTable(ctx context.Context, req *CreateTableRequest, opts ...call.Option) (*TableInfo, error) { - wireReq, err := createTableRequestToWire(req) +func (c *internalClient) CreateTable(ctx context.Context, req CreateTableRequest, opts ...call.Option) (*TableInfo, error) { + wireReq, err := createTableRequestToWire(&req) if err != nil { return nil, err } @@ -173,8 +173,8 @@ func (c *internalClient) CreateTable(ctx context.Context, req *CreateTableReques // the referenced parent table's catalog, the **USE_SCHEMA** privilege on the // referenced parent table's schema, and be the owner of the referenced parent // table. -func (c *internalClient) CreateTableConstraint(ctx context.Context, req *CreateTableConstraintRequest, opts ...call.Option) (*TableConstraint, error) { - wireReq, err := createTableConstraintRequestToWire(req) +func (c *internalClient) CreateTableConstraint(ctx context.Context, req CreateTableConstraintRequest, opts ...call.Option) (*TableConstraint, error) { + wireReq, err := createTableConstraintRequestToWire(&req) if err != nil { return nil, err } @@ -243,7 +243,7 @@ func (c *internalClient) CreateTableConstraint(ctx context.Context, req *CreateT // parent catalog and be the owner of the parent schema, or be the owner of the // table and have the **USE_CATALOG** privilege on the parent catalog and the // **USE_SCHEMA** privilege on the parent schema. -func (c *internalClient) DeleteTable(ctx context.Context, req *DeleteTableRequest, opts ...call.Option) (*DeleteTableResponse, error) { +func (c *internalClient) DeleteTable(ctx context.Context, req DeleteTableRequest, opts ...call.Option) (*DeleteTableResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -257,7 +257,11 @@ func (c *internalClient) DeleteTable(ctx context.Context, req *DeleteTableReques } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/tables/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -305,8 +309,8 @@ func (c *internalClient) DeleteTable(ctx context.Context, req *DeleteTableReques // the user must have the following permissions on all of the child tables: the // **USE_CATALOG** privilege on the table's catalog, the **USE_SCHEMA** // privilege on the table's schema, and be the owner of the table. -func (c *internalClient) DeleteTableConstraint(ctx context.Context, req *DeleteTableConstraintRequest, opts ...call.Option) (*DeleteTableConstraintResponse, error) { - wireReq, err := deleteTableConstraintRequestToWire(req) +func (c *internalClient) DeleteTableConstraint(ctx context.Context, req DeleteTableConstraintRequest, opts ...call.Option) (*DeleteTableConstraintResponse, error) { + wireReq, err := deleteTableConstraintRequestToWire(&req) if err != nil { return nil, err } @@ -323,7 +327,11 @@ func (c *internalClient) DeleteTableConstraint(ctx context.Context, req *DeleteT } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/constraints/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "constraint_name", wireReq.ConstraintName); err != nil { @@ -375,8 +383,8 @@ func (c *internalClient) DeleteTableConstraint(ctx context.Context, req *DeleteT // **USE_CATALOG** privilege on the parent catalog and the **USE_SCHEMA** // privilege on the parent schema, and either be the table owner or have the // **SELECT** privilege on the table. -func (c *internalClient) GetTable(ctx context.Context, req *GetTableRequest, opts ...call.Option) (*TableInfo, error) { - wireReq, err := getTableRequestToWire(req) +func (c *internalClient) GetTable(ctx context.Context, req GetTableRequest, opts ...call.Option) (*TableInfo, error) { + wireReq, err := getTableRequestToWire(&req) if err != nil { return nil, err } @@ -393,7 +401,11 @@ func (c *internalClient) GetTable(ctx context.Context, req *GetTableRequest, opt } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/tables/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "include_delta_metadata", wireReq.IncludeDeltaMetadata); err != nil { @@ -463,8 +475,8 @@ func (c *internalClient) GetTable(ctx context.Context, req *GetTableRequest, opt // results while still providing a next_page_token. Clients must continue // reading pages until next_page_token is absent, which is the only indication // that the end of results has been reached. -func (c *internalClient) ListTableSummaries(ctx context.Context, req *ListTableSummariesRequest, opts ...call.Option) (*ListTableSummariesResponse, error) { - wireReq, err := listTableSummariesRequestToWire(req) +func (c *internalClient) ListTableSummaries(ctx context.Context, req ListTableSummariesRequest, opts ...call.Option) (*ListTableSummariesResponse, error) { + wireReq, err := listTableSummariesRequestToWire(&req) if err != nil { return nil, err } @@ -546,7 +558,7 @@ func (c *internalClient) ListTableSummaries(ctx context.Context, req *ListTableS // // For example: // -// for item, err := range c.ListTableSummariesIter(ctx, &ListTableSummariesRequest{}) { +// for item, err := range c.ListTableSummariesIter(ctx, ListTableSummariesRequest{}) { // if err != nil { // return err // } @@ -558,16 +570,13 @@ func (c *internalClient) ListTableSummaries(ctx context.Context, req *ListTableS // // Callers who need custom pagination logic should use // ListTableSummaries directly. -func (c *internalClient) ListTableSummariesIter(ctx context.Context, req *ListTableSummariesRequest, opts ...call.Option) iter.Seq2[*TableSummary, error] { +func (c *internalClient) ListTableSummariesIter(ctx context.Context, req ListTableSummariesRequest, opts ...call.Option) iter.Seq2[*TableSummary, error] { return func(yield func(*TableSummary, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListTableSummariesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListTableSummaries(ctx, &pageReq, opts...) + resp, err := c.ListTableSummaries(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -602,8 +611,8 @@ func (c *internalClient) ListTableSummariesIter(ctx context.Context, req *ListTa // contain zero results while still providing a next_page_token. Clients must // continue reading pages until next_page_token is absent, which is the only // indication that the end of results has been reached. -func (c *internalClient) ListTables(ctx context.Context, req *ListTablesRequest, opts ...call.Option) (*ListTablesResponse, error) { - wireReq, err := listTablesRequestToWire(req) +func (c *internalClient) ListTables(ctx context.Context, req ListTablesRequest, opts ...call.Option) (*ListTablesResponse, error) { + wireReq, err := listTablesRequestToWire(&req) if err != nil { return nil, err } @@ -694,7 +703,7 @@ func (c *internalClient) ListTables(ctx context.Context, req *ListTablesRequest, // // For example: // -// for item, err := range c.ListTablesIter(ctx, &ListTablesRequest{}) { +// for item, err := range c.ListTablesIter(ctx, ListTablesRequest{}) { // if err != nil { // return err // } @@ -706,16 +715,13 @@ func (c *internalClient) ListTables(ctx context.Context, req *ListTablesRequest, // // Callers who need custom pagination logic should use // ListTables directly. -func (c *internalClient) ListTablesIter(ctx context.Context, req *ListTablesRequest, opts ...call.Option) iter.Seq2[*TableInfo, error] { +func (c *internalClient) ListTablesIter(ctx context.Context, req ListTablesRequest, opts ...call.Option) iter.Seq2[*TableInfo, error] { return func(yield func(*TableInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListTablesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListTables(ctx, &pageReq, opts...) + resp, err := c.ListTables(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -741,7 +747,7 @@ func (c *internalClient) ListTablesIter(ctx context.Context, req *ListTablesRequ // privilege on the parent schema, and either be the table owner or have the // **SELECT** privilege on the table. * Have **BROWSE** privilege on the parent // catalog * Have **BROWSE** privilege on the parent schema -func (c *internalClient) TableExists(ctx context.Context, req *TableExistsRequest, opts ...call.Option) (*TableExistsResponse, error) { +func (c *internalClient) TableExists(ctx context.Context, req TableExistsRequest, opts ...call.Option) (*TableExistsResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -755,7 +761,11 @@ func (c *internalClient) TableExists(ctx context.Context, req *TableExistsReques } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/tables/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } pb.literal("/exists") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -806,8 +816,8 @@ func (c *internalClient) TableExists(ctx context.Context, req *TableExistsReques // owner of the parent schema, or be the owner of the table and have the // **USE_CATALOG** privilege on the parent catalog and the **USE_SCHEMA** // privilege on the parent schema. -func (c *internalClient) UpdateTable(ctx context.Context, req *UpdateTableRequest, opts ...call.Option) (*UpdateTableResponse, error) { - wireReq, err := updateTableRequestToWire(req) +func (c *internalClient) UpdateTable(ctx context.Context, req UpdateTableRequest, opts ...call.Option) (*UpdateTableResponse, error) { + wireReq, err := updateTableRequestToWire(&req) if err != nil { return nil, err } @@ -828,7 +838,11 @@ func (c *internalClient) UpdateTable(ctx context.Context, req *UpdateTableReques } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/tables/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/uc/tables/v1/genhelper.go b/uc/tables/v1/genhelper.go old mode 100755 new mode 100644 index d1496c9..ce4fde4 --- a/uc/tables/v1/genhelper.go +++ b/uc/tables/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/tables/v1/model.go b/uc/tables/v1/model.go old mode 100755 new mode 100644 index 5464bdd..f62a5c9 --- a/uc/tables/v1/model.go +++ b/uc/tables/v1/model.go @@ -184,7 +184,11 @@ const ( SecurableType_Credential SecurableType = "CREDENTIAL" SecurableType_ExternalMetadata SecurableType = "EXTERNAL_METADATA" // TODO: [UC-2980] Staging tables aren't full-fleged securables yet. - SecurableType_StagingTable SecurableType = "STAGING_TABLE" + SecurableType_StagingTable SecurableType = "STAGING_TABLE" + SecurableType_Model SecurableType = "MODEL" + SecurableType_ModelService SecurableType = "MODEL_SERVICE" + SecurableType_McpService SecurableType = "MCP_SERVICE" + SecurableType_ModelProviderService SecurableType = "MODEL_PROVIDER_SERVICE" ) type SseEncryptionAlgorithm string @@ -273,10 +277,9 @@ type ColumnMask struct { // column being masked and the types of the rest of the args should match the // types of columns in 'using_column_names'. UsingColumnNames []string - // The list of additional table columns or literals to be passed as additional - // arguments to a column mask function. This is the replacement of the - // deprecated using_column_names field and carries information about the types - // (alias or constant) of the arguments to the mask function. + // The list of table columns or literals to be passed as additional arguments to + // a column mask function, carrying the type (column reference vs constant + // literal) of each argument. Deprecated: use using_column_names instead. UsingArguments []PolicyFunctionArgument } @@ -667,10 +670,9 @@ type RowFilter struct { // The list of table columns to be passed as input to the row filter function. // The column types should match the types of the filter function arguments. InputColumnNames []string - // The list of additional table columns or literals to be passed as additional - // arguments to a row filter function. This is the replacement of the deprecated - // input_column_names field and carries information about the types (alias or - // constant) of the arguments to the filter function. + // The list of table columns or literals to be passed as additional arguments to + // a row filter function, carrying the type (column reference vs constant + // literal) of each argument. Deprecated: use input_column_names instead. InputArguments []PolicyFunctionArgument } diff --git a/uc/tables/v1/wire.go b/uc/tables/v1/wire.go old mode 100755 new mode 100644 index 05ed2a2..1385f7b --- a/uc/tables/v1/wire.go +++ b/uc/tables/v1/wire.go @@ -3,9 +3,55 @@ package tables import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type columnInfoWire struct { Name *string `json:"name,omitempty"` TypeText *string `json:"type_text,omitempty"` @@ -166,13 +212,13 @@ type createTableRequestWire struct { MetastoreId *string `json:"metastore_id,omitempty"` FullName *string `json:"full_name,omitempty"` DataAccessConfigurationId *string `json:"data_access_configuration_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` TableId *string `json:"table_id,omitempty"` DeltaRuntimePropertiesKvpairs *deltaRuntimePropertiesKvPairsWire `json:"delta_runtime_properties_kvpairs,omitempty"` - DeletedAt *int64 `json:"deleted_at,omitempty"` + DeletedAt *wireInt64 `json:"deleted_at,omitempty"` EffectivePredictiveOptimizationFlag *effectivePredictiveOptimizationFlagWire `json:"effective_predictive_optimization_flag,omitempty"` AccessPoint *string `json:"access_point,omitempty"` BrowseOnly *bool `json:"browse_only,omitempty"` @@ -198,10 +244,22 @@ func createTableRequestToWire(v *CreateTableRequest) (*createTableRequestWire, e if err != nil { return nil, fmt.Errorf("%s: %w", "CreateTableRequest.RowFilter", err) } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateTableRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateTableRequest.UpdatedAt", err) + } deltaRuntimePropertiesKvpairsWireValue, err := deltaRuntimePropertiesKvPairsToWire(v.DeltaRuntimePropertiesKvpairs) if err != nil { return nil, fmt.Errorf("%s: %w", "CreateTableRequest.DeltaRuntimePropertiesKvpairs", err) } + deletedAtWireValue, err := int64ToWire(v.DeletedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateTableRequest.DeletedAt", err) + } effectivePredictiveOptimizationFlagWireValue, err := effectivePredictiveOptimizationFlagToWire(v.EffectivePredictiveOptimizationFlag) if err != nil { return nil, fmt.Errorf("%s: %w", "CreateTableRequest.EffectivePredictiveOptimizationFlag", err) @@ -238,13 +296,13 @@ func createTableRequestToWire(v *CreateTableRequest) (*createTableRequestWire, e MetastoreId: v.MetastoreId, FullName: v.FullName, DataAccessConfigurationId: v.DataAccessConfigurationId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, TableId: v.TableId, DeltaRuntimePropertiesKvpairs: deltaRuntimePropertiesKvpairsWireValue, - DeletedAt: v.DeletedAt, + DeletedAt: deletedAtWireValue, EffectivePredictiveOptimizationFlag: effectivePredictiveOptimizationFlagWireValue, AccessPoint: v.AccessPoint, BrowseOnly: v.BrowseOnly, @@ -1123,13 +1181,13 @@ type tableInfoWire struct { MetastoreId *string `json:"metastore_id,omitempty"` FullName *string `json:"full_name,omitempty"` DataAccessConfigurationId *string `json:"data_access_configuration_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` TableId *string `json:"table_id,omitempty"` DeltaRuntimePropertiesKvpairs *deltaRuntimePropertiesKvPairsWire `json:"delta_runtime_properties_kvpairs,omitempty"` - DeletedAt *int64 `json:"deleted_at,omitempty"` + DeletedAt *wireInt64 `json:"deleted_at,omitempty"` EffectivePredictiveOptimizationFlag *effectivePredictiveOptimizationFlagWire `json:"effective_predictive_optimization_flag,omitempty"` AccessPoint *string `json:"access_point,omitempty"` BrowseOnly *bool `json:"browse_only,omitempty"` @@ -1155,10 +1213,22 @@ func tableInfoFromWire(w *tableInfoWire) (*TableInfo, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "TableInfo.RowFilter", err) } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TableInfo.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TableInfo.UpdatedAt", err) + } deltaRuntimePropertiesKvpairsPublicValue, err := deltaRuntimePropertiesKvPairsFromWire(w.DeltaRuntimePropertiesKvpairs) if err != nil { return nil, fmt.Errorf("%s: %w", "TableInfo.DeltaRuntimePropertiesKvpairs", err) } + deletedAtPublicValue, err := int64FromWire(w.DeletedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "TableInfo.DeletedAt", err) + } effectivePredictiveOptimizationFlagPublicValue, err := effectivePredictiveOptimizationFlagFromWire(w.EffectivePredictiveOptimizationFlag) if err != nil { return nil, fmt.Errorf("%s: %w", "TableInfo.EffectivePredictiveOptimizationFlag", err) @@ -1195,13 +1265,13 @@ func tableInfoFromWire(w *tableInfoWire) (*TableInfo, error) { MetastoreId: w.MetastoreId, FullName: w.FullName, DataAccessConfigurationId: w.DataAccessConfigurationId, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, TableId: w.TableId, DeltaRuntimePropertiesKvpairs: deltaRuntimePropertiesKvpairsPublicValue, - DeletedAt: w.DeletedAt, + DeletedAt: deletedAtPublicValue, EffectivePredictiveOptimizationFlag: effectivePredictiveOptimizationFlagPublicValue, AccessPoint: w.AccessPoint, BrowseOnly: w.BrowseOnly, @@ -1254,13 +1324,13 @@ type updateTableRequestWire struct { MetastoreId *string `json:"metastore_id,omitempty"` FullName *string `json:"full_name,omitempty"` DataAccessConfigurationId *string `json:"data_access_configuration_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` TableId *string `json:"table_id,omitempty"` DeltaRuntimePropertiesKvpairs *deltaRuntimePropertiesKvPairsWire `json:"delta_runtime_properties_kvpairs,omitempty"` - DeletedAt *int64 `json:"deleted_at,omitempty"` + DeletedAt *wireInt64 `json:"deleted_at,omitempty"` EffectivePredictiveOptimizationFlag *effectivePredictiveOptimizationFlagWire `json:"effective_predictive_optimization_flag,omitempty"` AccessPoint *string `json:"access_point,omitempty"` BrowseOnly *bool `json:"browse_only,omitempty"` @@ -1286,10 +1356,22 @@ func updateTableRequestToWire(v *UpdateTableRequest) (*updateTableRequestWire, e if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateTableRequest.RowFilter", err) } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateTableRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateTableRequest.UpdatedAt", err) + } deltaRuntimePropertiesKvpairsWireValue, err := deltaRuntimePropertiesKvPairsToWire(v.DeltaRuntimePropertiesKvpairs) if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateTableRequest.DeltaRuntimePropertiesKvpairs", err) } + deletedAtWireValue, err := int64ToWire(v.DeletedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateTableRequest.DeletedAt", err) + } effectivePredictiveOptimizationFlagWireValue, err := effectivePredictiveOptimizationFlagToWire(v.EffectivePredictiveOptimizationFlag) if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateTableRequest.EffectivePredictiveOptimizationFlag", err) @@ -1327,13 +1409,13 @@ func updateTableRequestToWire(v *UpdateTableRequest) (*updateTableRequestWire, e MetastoreId: v.MetastoreId, FullName: v.FullName, DataAccessConfigurationId: v.DataAccessConfigurationId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, TableId: v.TableId, DeltaRuntimePropertiesKvpairs: deltaRuntimePropertiesKvpairsWireValue, - DeletedAt: v.DeletedAt, + DeletedAt: deletedAtWireValue, EffectivePredictiveOptimizationFlag: effectivePredictiveOptimizationFlagWireValue, AccessPoint: v.AccessPoint, BrowseOnly: v.BrowseOnly, diff --git a/uc/volumes/CHANGELOG.md b/uc/volumes/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/volumes/CHANGELOG.md +++ b/uc/volumes/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/volumes/go.mod b/uc/volumes/go.mod index a71ddb5..56984f5 100644 --- a/uc/volumes/go.mod +++ b/uc/volumes/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/volumes/internal/version.go b/uc/volumes/internal/version.go index 79f1552..042875a 100644 --- a/uc/volumes/internal/version.go +++ b/uc/volumes/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-volumes" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/volumes/v1/client.go b/uc/volumes/v1/client.go old mode 100755 new mode 100644 index 89333dc..97fc81c --- a/uc/volumes/v1/client.go +++ b/uc/volumes/v1/client.go @@ -92,8 +92,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // location. - There are no other tables, nor volumes existing in the specified // storage location. - The specified storage location is not under the location // of other tables, nor volumes, or catalogs or schemas. -func (c *internalClient) CreateVolume(ctx context.Context, req *CreateVolumeRequest, opts ...call.Option) (*VolumeInfo, error) { - wireReq, err := createVolumeRequestToWire(req) +func (c *internalClient) CreateVolume(ctx context.Context, req CreateVolumeRequest, opts ...call.Option) (*VolumeInfo, error) { + wireReq, err := createVolumeRequestToWire(&req) if err != nil { return nil, err } @@ -163,7 +163,7 @@ func (c *internalClient) CreateVolume(ctx context.Context, req *CreateVolumeRequ // latter case, the caller must also be the owner or have the **USE_CATALOG** // privilege on the parent catalog and the **USE_SCHEMA** privilege on the // parent schema. -func (c *internalClient) DeleteVolume(ctx context.Context, req *DeleteVolumeRequest, opts ...call.Option) (*DeleteVolumeResponse, error) { +func (c *internalClient) DeleteVolume(ctx context.Context, req DeleteVolumeRequest, opts ...call.Option) (*DeleteVolumeResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -177,7 +177,11 @@ func (c *internalClient) DeleteVolume(ctx context.Context, req *DeleteVolumeRequ } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/volumes/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -222,8 +226,8 @@ func (c *internalClient) DeleteVolume(ctx context.Context, req *DeleteVolumeRequ // VOLUME** privilege on) the volume. For the latter case, the caller must also // be the owner or have the **USE_CATALOG** privilege on the parent catalog and // the **USE_SCHEMA** privilege on the parent schema. -func (c *internalClient) GetVolume(ctx context.Context, req *GetVolumeRequest, opts ...call.Option) (*VolumeInfo, error) { - wireReq, err := getVolumeRequestToWire(req) +func (c *internalClient) GetVolume(ctx context.Context, req GetVolumeRequest, opts ...call.Option) (*VolumeInfo, error) { + wireReq, err := getVolumeRequestToWire(&req) if err != nil { return nil, err } @@ -240,7 +244,11 @@ func (c *internalClient) GetVolume(ctx context.Context, req *GetVolumeRequest, o } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/volumes/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "include_browse", wireReq.IncludeBrowse); err != nil { @@ -304,8 +312,8 @@ func (c *internalClient) GetVolume(ctx context.Context, req *GetVolumeRequest, o // results while still providing a next_page_token. Clients must continue // reading pages until next_page_token is absent, which is the only indication // that the end of results has been reached. -func (c *internalClient) ListVolumes(ctx context.Context, req *ListVolumesRequest, opts ...call.Option) (*ListVolumesResponse, error) { - wireReq, err := listVolumesRequestToWire(req) +func (c *internalClient) ListVolumes(ctx context.Context, req ListVolumesRequest, opts ...call.Option) (*ListVolumesResponse, error) { + wireReq, err := listVolumesRequestToWire(&req) if err != nil { return nil, err } @@ -384,7 +392,7 @@ func (c *internalClient) ListVolumes(ctx context.Context, req *ListVolumesReques // // For example: // -// for item, err := range c.ListVolumesIter(ctx, &ListVolumesRequest{}) { +// for item, err := range c.ListVolumesIter(ctx, ListVolumesRequest{}) { // if err != nil { // return err // } @@ -396,16 +404,13 @@ func (c *internalClient) ListVolumes(ctx context.Context, req *ListVolumesReques // // Callers who need custom pagination logic should use // ListVolumes directly. -func (c *internalClient) ListVolumesIter(ctx context.Context, req *ListVolumesRequest, opts ...call.Option) iter.Seq2[*VolumeInfo, error] { +func (c *internalClient) ListVolumesIter(ctx context.Context, req ListVolumesRequest, opts ...call.Option) iter.Seq2[*VolumeInfo, error] { return func(yield func(*VolumeInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListVolumesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListVolumes(ctx, &pageReq, opts...) + resp, err := c.ListVolumes(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -432,8 +437,8 @@ func (c *internalClient) ListVolumesIter(ctx context.Context, req *ListVolumesRe // // Currently only the name, the owner or the comment of the volume could be // updated. -func (c *internalClient) UpdateVolume(ctx context.Context, req *UpdateVolumeRequest, opts ...call.Option) (*VolumeInfo, error) { - wireReq, err := updateVolumeRequestToWire(req) +func (c *internalClient) UpdateVolume(ctx context.Context, req UpdateVolumeRequest, opts ...call.Option) (*VolumeInfo, error) { + wireReq, err := updateVolumeRequestToWire(&req) if err != nil { return nil, err } @@ -454,7 +459,11 @@ func (c *internalClient) UpdateVolume(ctx context.Context, req *UpdateVolumeRequ } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/volumes/") - pb.singleSegment(*req.FullNameArg) + if req.FullNameArg == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.FullNameArg) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/uc/volumes/v1/genhelper.go b/uc/volumes/v1/genhelper.go old mode 100755 new mode 100644 index 9529a5e..93b0e32 --- a/uc/volumes/v1/genhelper.go +++ b/uc/volumes/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/volumes/v1/wire.go b/uc/volumes/v1/wire.go old mode 100755 new mode 100644 index 8d12990..0573c69 --- a/uc/volumes/v1/wire.go +++ b/uc/volumes/v1/wire.go @@ -3,9 +3,55 @@ package volumes import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type createVolumeRequestWire struct { Name *string `json:"name,omitempty"` CatalogName *string `json:"catalog_name,omitempty"` @@ -17,9 +63,9 @@ type createVolumeRequestWire struct { FullName *string `json:"full_name,omitempty"` VolumeId *string `json:"volume_id,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` AccessPoint *string `json:"access_point,omitempty"` EncryptionDetails *encryptionDetailsWire `json:"encryption_details,omitempty"` @@ -30,6 +76,14 @@ func createVolumeRequestToWire(v *CreateVolumeRequest) (*createVolumeRequestWire if v == nil { return nil, nil } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateVolumeRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateVolumeRequest.UpdatedAt", err) + } encryptionDetailsWireValue, err := encryptionDetailsToWire(v.EncryptionDetails) if err != nil { return nil, fmt.Errorf("%s: %w", "CreateVolumeRequest.EncryptionDetails", err) @@ -45,9 +99,9 @@ func createVolumeRequestToWire(v *CreateVolumeRequest) (*createVolumeRequestWire FullName: v.FullName, VolumeId: v.VolumeId, MetastoreId: v.MetastoreId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, AccessPoint: v.AccessPoint, EncryptionDetails: encryptionDetailsWireValue, @@ -200,9 +254,9 @@ type updateVolumeRequestWire struct { FullName *string `json:"full_name,omitempty"` VolumeId *string `json:"volume_id,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` AccessPoint *string `json:"access_point,omitempty"` EncryptionDetails *encryptionDetailsWire `json:"encryption_details,omitempty"` @@ -213,6 +267,14 @@ func updateVolumeRequestToWire(v *UpdateVolumeRequest) (*updateVolumeRequestWire if v == nil { return nil, nil } + createdAtWireValue, err := int64ToWire(v.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateVolumeRequest.CreatedAt", err) + } + updatedAtWireValue, err := int64ToWire(v.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateVolumeRequest.UpdatedAt", err) + } encryptionDetailsWireValue, err := encryptionDetailsToWire(v.EncryptionDetails) if err != nil { return nil, fmt.Errorf("%s: %w", "UpdateVolumeRequest.EncryptionDetails", err) @@ -230,9 +292,9 @@ func updateVolumeRequestToWire(v *UpdateVolumeRequest) (*updateVolumeRequestWire FullName: v.FullName, VolumeId: v.VolumeId, MetastoreId: v.MetastoreId, - CreatedAt: v.CreatedAt, + CreatedAt: createdAtWireValue, CreatedBy: v.CreatedBy, - UpdatedAt: v.UpdatedAt, + UpdatedAt: updatedAtWireValue, UpdatedBy: v.UpdatedBy, AccessPoint: v.AccessPoint, EncryptionDetails: encryptionDetailsWireValue, @@ -251,9 +313,9 @@ type volumeInfoWire struct { FullName *string `json:"full_name,omitempty"` VolumeId *string `json:"volume_id,omitempty"` MetastoreId *string `json:"metastore_id,omitempty"` - CreatedAt *int64 `json:"created_at,omitempty"` + CreatedAt *wireInt64 `json:"created_at,omitempty"` CreatedBy *string `json:"created_by,omitempty"` - UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedAt *wireInt64 `json:"updated_at,omitempty"` UpdatedBy *string `json:"updated_by,omitempty"` AccessPoint *string `json:"access_point,omitempty"` EncryptionDetails *encryptionDetailsWire `json:"encryption_details,omitempty"` @@ -264,6 +326,14 @@ func volumeInfoFromWire(w *volumeInfoWire) (*VolumeInfo, error) { if w == nil { return nil, nil } + createdAtPublicValue, err := int64FromWire(w.CreatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "VolumeInfo.CreatedAt", err) + } + updatedAtPublicValue, err := int64FromWire(w.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("%s: %w", "VolumeInfo.UpdatedAt", err) + } encryptionDetailsPublicValue, err := encryptionDetailsFromWire(w.EncryptionDetails) if err != nil { return nil, fmt.Errorf("%s: %w", "VolumeInfo.EncryptionDetails", err) @@ -279,9 +349,9 @@ func volumeInfoFromWire(w *volumeInfoWire) (*VolumeInfo, error) { FullName: w.FullName, VolumeId: w.VolumeId, MetastoreId: w.MetastoreId, - CreatedAt: w.CreatedAt, + CreatedAt: createdAtPublicValue, CreatedBy: w.CreatedBy, - UpdatedAt: w.UpdatedAt, + UpdatedAt: updatedAtPublicValue, UpdatedBy: w.UpdatedBy, AccessPoint: w.AccessPoint, EncryptionDetails: encryptionDetailsPublicValue, diff --git a/uc/workspacebindings/CHANGELOG.md b/uc/workspacebindings/CHANGELOG.md index 6224c04..19f237c 100644 --- a/uc/workspacebindings/CHANGELOG.md +++ b/uc/workspacebindings/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/uc/workspacebindings/go.mod b/uc/workspacebindings/go.mod index 5b829fe..8695909 100644 --- a/uc/workspacebindings/go.mod +++ b/uc/workspacebindings/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../../core replace github.com/databricks/sdk-go/options => ../../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/uc/workspacebindings/internal/version.go b/uc/workspacebindings/internal/version.go index 23f2d8d..ce89a2a 100644 --- a/uc/workspacebindings/internal/version.go +++ b/uc/workspacebindings/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-uc-workspacebindings" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/uc/workspacebindings/v1/client.go b/uc/workspacebindings/v1/client.go old mode 100755 new mode 100644 index 1c0aa53..5b1110c --- a/uc/workspacebindings/v1/client.go +++ b/uc/workspacebindings/v1/client.go @@ -76,7 +76,7 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Gets workspace bindings of the catalog. The caller must be a metastore admin // or an owner of the catalog. -func (c *internalClient) GetCatalogWorkspaceBindings(ctx context.Context, req *GetCatalogWorkspaceBindingsRequest, opts ...call.Option) (*GetCatalogWorkspaceBindingsResponse, error) { +func (c *internalClient) GetCatalogWorkspaceBindings(ctx context.Context, req GetCatalogWorkspaceBindingsRequest, opts ...call.Option) (*GetCatalogWorkspaceBindingsResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -90,7 +90,11 @@ func (c *internalClient) GetCatalogWorkspaceBindings(ctx context.Context, req *G } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/workspace-bindings/catalogs/") - pb.singleSegment(*req.CatalogName) + if req.CatalogName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CatalogName) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -145,8 +149,8 @@ func (c *internalClient) GetCatalogWorkspaceBindings(ctx context.Context, req *G // contain zero results while still providing a next_page_token. Clients must // continue reading pages until next_page_token is absent, which is the only // indication that the end of results has been reached. -func (c *internalClient) GetWorkspaceBindings(ctx context.Context, req *GetWorkspaceBindingsRequest, opts ...call.Option) (*GetWorkspaceBindingsResponse, error) { - wireReq, err := getWorkspaceBindingsRequestToWire(req) +func (c *internalClient) GetWorkspaceBindings(ctx context.Context, req GetWorkspaceBindingsRequest, opts ...call.Option) (*GetWorkspaceBindingsResponse, error) { + wireReq, err := getWorkspaceBindingsRequestToWire(&req) if err != nil { return nil, err } @@ -163,9 +167,17 @@ func (c *internalClient) GetWorkspaceBindings(ctx context.Context, req *GetWorks } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/bindings/") - pb.singleSegment(*req.SecurableType) + if req.SecurableType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SecurableType) + } pb.literal("/") - pb.singleSegment(*req.SecurableFullName) + if req.SecurableFullName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SecurableFullName) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "max_results", wireReq.MaxResults); err != nil { @@ -221,7 +233,7 @@ func (c *internalClient) GetWorkspaceBindings(ctx context.Context, req *GetWorks // // For example: // -// for item, err := range c.GetWorkspaceBindingsIter(ctx, &GetWorkspaceBindingsRequest{}) { +// for item, err := range c.GetWorkspaceBindingsIter(ctx, GetWorkspaceBindingsRequest{}) { // if err != nil { // return err // } @@ -233,16 +245,13 @@ func (c *internalClient) GetWorkspaceBindings(ctx context.Context, req *GetWorks // // Callers who need custom pagination logic should use // GetWorkspaceBindings directly. -func (c *internalClient) GetWorkspaceBindingsIter(ctx context.Context, req *GetWorkspaceBindingsRequest, opts ...call.Option) iter.Seq2[*WorkspaceBindingInfo, error] { +func (c *internalClient) GetWorkspaceBindingsIter(ctx context.Context, req GetWorkspaceBindingsRequest, opts ...call.Option) iter.Seq2[*WorkspaceBindingInfo, error] { return func(yield func(*WorkspaceBindingInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := GetWorkspaceBindingsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.GetWorkspaceBindings(ctx, &pageReq, opts...) + resp, err := c.GetWorkspaceBindings(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -262,8 +271,8 @@ func (c *internalClient) GetWorkspaceBindingsIter(ctx context.Context, req *GetW // Updates workspace bindings of the catalog. The caller must be a metastore // admin or an owner of the catalog. -func (c *internalClient) UpdateCatalogWorkspaceBindings(ctx context.Context, req *UpdateCatalogWorkspaceBindingsRequest, opts ...call.Option) (*UpdateCatalogWorkspaceBindingsResponse, error) { - wireReq, err := updateCatalogWorkspaceBindingsRequestToWire(req) +func (c *internalClient) UpdateCatalogWorkspaceBindings(ctx context.Context, req UpdateCatalogWorkspaceBindingsRequest, opts ...call.Option) (*UpdateCatalogWorkspaceBindingsResponse, error) { + wireReq, err := updateCatalogWorkspaceBindingsRequestToWire(&req) if err != nil { return nil, err } @@ -284,7 +293,11 @@ func (c *internalClient) UpdateCatalogWorkspaceBindings(ctx context.Context, req } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/workspace-bindings/catalogs/") - pb.singleSegment(*req.CatalogName) + if req.CatalogName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CatalogName) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -332,8 +345,8 @@ func (c *internalClient) UpdateCatalogWorkspaceBindings(ctx context.Context, req // Updates workspace bindings of the securable. The caller must be a metastore // admin or an owner of the securable. -func (c *internalClient) UpdateWorkspaceBindings(ctx context.Context, req *UpdateWorkspaceBindingsRequest, opts ...call.Option) (*UpdateWorkspaceBindingsResponse, error) { - wireReq, err := updateWorkspaceBindingsRequestToWire(req) +func (c *internalClient) UpdateWorkspaceBindings(ctx context.Context, req UpdateWorkspaceBindingsRequest, opts ...call.Option) (*UpdateWorkspaceBindingsResponse, error) { + wireReq, err := updateWorkspaceBindingsRequestToWire(&req) if err != nil { return nil, err } @@ -354,9 +367,17 @@ func (c *internalClient) UpdateWorkspaceBindings(ctx context.Context, req *Updat } pb := pathBuilder{} pb.literal("/api/2.1/unity-catalog/bindings/") - pb.singleSegment(*req.SecurableType) + if req.SecurableType == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SecurableType) + } pb.literal("/") - pb.singleSegment(*req.SecurableFullName) + if req.SecurableFullName == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.SecurableFullName) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() diff --git a/uc/workspacebindings/v1/genhelper.go b/uc/workspacebindings/v1/genhelper.go old mode 100755 new mode 100644 index 0a7689b..121cb18 --- a/uc/workspacebindings/v1/genhelper.go +++ b/uc/workspacebindings/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/uc/workspacebindings/v1/wire.go b/uc/workspacebindings/v1/wire.go old mode 100755 new mode 100644 index 362e5dd..64b44e8 --- a/uc/workspacebindings/v1/wire.go +++ b/uc/workspacebindings/v1/wire.go @@ -3,19 +3,69 @@ package workspacebindings import ( + "bytes" + "encoding/json" "fmt" + "strconv" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type getCatalogWorkspaceBindingsResponseWire struct { - Workspaces []int64 `json:"workspaces,omitempty"` + Workspaces []wireInt64 `json:"workspaces,omitempty"` } func getCatalogWorkspaceBindingsResponseFromWire(w *getCatalogWorkspaceBindingsResponseWire) (*GetCatalogWorkspaceBindingsResponse, error) { if w == nil { return nil, nil } + workspacesPublicValue, err := convertSlice(w.Workspaces, int64FromWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetCatalogWorkspaceBindingsResponse.Workspaces", err) + } return &GetCatalogWorkspaceBindingsResponse{ - Workspaces: w.Workspaces, + Workspaces: workspacesPublicValue, }, nil } @@ -58,32 +108,44 @@ func getWorkspaceBindingsResponseFromWire(w *getWorkspaceBindingsResponseWire) ( } type updateCatalogWorkspaceBindingsRequestWire struct { - CatalogName *string `json:"catalog_name,omitempty"` - AssignWorkspaces []int64 `json:"assign_workspaces,omitempty"` - UnassignWorkspaces []int64 `json:"unassign_workspaces,omitempty"` + CatalogName *string `json:"catalog_name,omitempty"` + AssignWorkspaces []wireInt64 `json:"assign_workspaces,omitempty"` + UnassignWorkspaces []wireInt64 `json:"unassign_workspaces,omitempty"` } func updateCatalogWorkspaceBindingsRequestToWire(v *UpdateCatalogWorkspaceBindingsRequest) (*updateCatalogWorkspaceBindingsRequestWire, error) { if v == nil { return nil, nil } + assignWorkspacesWireValue, err := convertSlice(v.AssignWorkspaces, int64ToWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateCatalogWorkspaceBindingsRequest.AssignWorkspaces", err) + } + unassignWorkspacesWireValue, err := convertSlice(v.UnassignWorkspaces, int64ToWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateCatalogWorkspaceBindingsRequest.UnassignWorkspaces", err) + } return &updateCatalogWorkspaceBindingsRequestWire{ CatalogName: v.CatalogName, - AssignWorkspaces: v.AssignWorkspaces, - UnassignWorkspaces: v.UnassignWorkspaces, + AssignWorkspaces: assignWorkspacesWireValue, + UnassignWorkspaces: unassignWorkspacesWireValue, }, nil } type updateCatalogWorkspaceBindingsResponseWire struct { - Workspaces []int64 `json:"workspaces,omitempty"` + Workspaces []wireInt64 `json:"workspaces,omitempty"` } func updateCatalogWorkspaceBindingsResponseFromWire(w *updateCatalogWorkspaceBindingsResponseWire) (*UpdateCatalogWorkspaceBindingsResponse, error) { if w == nil { return nil, nil } + workspacesPublicValue, err := convertSlice(w.Workspaces, int64FromWire) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpdateCatalogWorkspaceBindingsResponse.Workspaces", err) + } return &UpdateCatalogWorkspaceBindingsResponse{ - Workspaces: w.Workspaces, + Workspaces: workspacesPublicValue, }, nil } @@ -132,7 +194,7 @@ func updateWorkspaceBindingsResponseFromWire(w *updateWorkspaceBindingsResponseW } type workspaceBindingInfoWire struct { - WorkspaceId *int64 `json:"workspace_id,omitempty"` + WorkspaceId *wireInt64 `json:"workspace_id,omitempty"` BindingType BindingType `json:"binding_type,omitempty"` } @@ -140,8 +202,12 @@ func workspaceBindingInfoToWire(v *WorkspaceBindingInfo) (*workspaceBindingInfoW if v == nil { return nil, nil } + workspaceIdWireValue, err := int64ToWire(v.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "WorkspaceBindingInfo.WorkspaceId", err) + } return &workspaceBindingInfoWire{ - WorkspaceId: v.WorkspaceId, + WorkspaceId: workspaceIdWireValue, BindingType: v.BindingType, }, nil } @@ -150,8 +216,12 @@ func workspaceBindingInfoFromWire(w *workspaceBindingInfoWire) (*WorkspaceBindin if w == nil { return nil, nil } + workspaceIdPublicValue, err := int64FromWire(w.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "WorkspaceBindingInfo.WorkspaceId", err) + } return &WorkspaceBindingInfo{ - WorkspaceId: w.WorkspaceId, + WorkspaceId: workspaceIdPublicValue, BindingType: w.BindingType, }, nil } diff --git a/usagedashboards/CHANGELOG.md b/usagedashboards/CHANGELOG.md index 6224c04..19f237c 100644 --- a/usagedashboards/CHANGELOG.md +++ b/usagedashboards/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/usagedashboards/go.mod b/usagedashboards/go.mod index 7780de1..9918bb4 100644 --- a/usagedashboards/go.mod +++ b/usagedashboards/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/usagedashboards/internal/version.go b/usagedashboards/internal/version.go index d9f9448..950720d 100644 --- a/usagedashboards/internal/version.go +++ b/usagedashboards/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-usagedashboards" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/usagedashboards/v1/client.go b/usagedashboards/v1/client.go old mode 100755 new mode 100644 index cb1054f..0c457fc --- a/usagedashboards/v1/client.go +++ b/usagedashboards/v1/client.go @@ -76,8 +76,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Create a usage dashboard specified by workspaceId, accountId, and dashboard // type. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) CreateBillingUsageDashboard(ctx context.Context, req *CreateBillingUsageDashboardRequest, opts ...call.Option) (*CreateBillingUsageDashboardResponse, error) { - wireReq, err := createBillingUsageDashboardRequestToWire(req) +func (c *internalClient) CreateBillingUsageDashboard(ctx context.Context, req CreateBillingUsageDashboardRequest, opts ...call.Option) (*CreateBillingUsageDashboardResponse, error) { + wireReq, err := createBillingUsageDashboardRequestToWire(&req) if err != nil { return nil, err } @@ -149,8 +149,8 @@ func (c *internalClient) CreateBillingUsageDashboard(ctx context.Context, req *C // Get a usage dashboard specified by workspaceId, accountId, and dashboard // type. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetBillingUsageDashboard(ctx context.Context, req *GetBillingUsageDashboardRequest, opts ...call.Option) (*GetBillingUsageDashboardResponse, error) { - wireReq, err := getBillingUsageDashboardRequestToWire(req) +func (c *internalClient) GetBillingUsageDashboard(ctx context.Context, req GetBillingUsageDashboardRequest, opts ...call.Option) (*GetBillingUsageDashboardResponse, error) { + wireReq, err := getBillingUsageDashboardRequestToWire(&req) if err != nil { return nil, err } diff --git a/usagedashboards/v1/genhelper.go b/usagedashboards/v1/genhelper.go old mode 100755 new mode 100644 index 036e82d..72b75c2 --- a/usagedashboards/v1/genhelper.go +++ b/usagedashboards/v1/genhelper.go @@ -178,11 +178,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -195,13 +196,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/usagedashboards/v1/wire.go b/usagedashboards/v1/wire.go old mode 100755 new mode 100644 index 9da6bca..b3d4e67 --- a/usagedashboards/v1/wire.go +++ b/usagedashboards/v1/wire.go @@ -2,8 +2,58 @@ package usagedashboards +import ( + "bytes" + "encoding/json" + "fmt" + "strconv" +) + +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type createBillingUsageDashboardRequestWire struct { - WorkspaceId *int64 `json:"workspace_id,omitempty"` + WorkspaceId *wireInt64 `json:"workspace_id,omitempty"` AccountId *string `json:"account_id,omitempty"` DashboardType UsageDashboardType `json:"dashboard_type,omitempty"` MajorVersion UsageDashboardMajorVersion `json:"major_version,omitempty"` @@ -13,8 +63,12 @@ func createBillingUsageDashboardRequestToWire(v *CreateBillingUsageDashboardRequ if v == nil { return nil, nil } + workspaceIdWireValue, err := int64ToWire(v.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateBillingUsageDashboardRequest.WorkspaceId", err) + } return &createBillingUsageDashboardRequestWire{ - WorkspaceId: v.WorkspaceId, + WorkspaceId: workspaceIdWireValue, AccountId: v.AccountId, DashboardType: v.DashboardType, MajorVersion: v.MajorVersion, @@ -35,7 +89,7 @@ func createBillingUsageDashboardResponseFromWire(w *createBillingUsageDashboardR } type getBillingUsageDashboardRequestWire struct { - WorkspaceId *int64 `json:"workspace_id,omitempty"` + WorkspaceId *wireInt64 `json:"workspace_id,omitempty"` AccountId *string `json:"account_id,omitempty"` DashboardType UsageDashboardType `json:"dashboard_type,omitempty"` } @@ -44,8 +98,12 @@ func getBillingUsageDashboardRequestToWire(v *GetBillingUsageDashboardRequest) ( if v == nil { return nil, nil } + workspaceIdWireValue, err := int64ToWire(v.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetBillingUsageDashboardRequest.WorkspaceId", err) + } return &getBillingUsageDashboardRequestWire{ - WorkspaceId: v.WorkspaceId, + WorkspaceId: workspaceIdWireValue, AccountId: v.AccountId, DashboardType: v.DashboardType, }, nil diff --git a/vectorsearch/CHANGELOG.md b/vectorsearch/CHANGELOG.md index 6224c04..19f237c 100644 --- a/vectorsearch/CHANGELOG.md +++ b/vectorsearch/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/vectorsearch/go.mod b/vectorsearch/go.mod index 46fd746..1b8a59f 100644 --- a/vectorsearch/go.mod +++ b/vectorsearch/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/vectorsearch/internal/version.go b/vectorsearch/internal/version.go index 6e161cb..ee64365 100644 --- a/vectorsearch/internal/version.go +++ b/vectorsearch/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-vectorsearch" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/vectorsearch/v1/client.go b/vectorsearch/v1/client.go old mode 100755 new mode 100644 index 30c7cd5..15abf09 --- a/vectorsearch/v1/client.go +++ b/vectorsearch/v1/client.go @@ -77,8 +77,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { } // Create a new endpoint. -func (c *internalClient) createEndpointBase(ctx context.Context, req *CreateEndpointRequest, opts ...call.Option) (*Endpoint, error) { - wireReq, err := createEndpointRequestToWire(req) +func (c *internalClient) createEndpointBase(ctx context.Context, req CreateEndpointRequest, opts ...call.Option) (*Endpoint, error) { + wireReq, err := createEndpointRequestToWire(&req) if err != nil { return nil, err } @@ -143,7 +143,7 @@ func (c *internalClient) createEndpointBase(ctx context.Context, req *CreateEndp } // Create a new endpoint. -func (c *internalClient) CreateEndpoint(ctx context.Context, req *CreateEndpointRequest, opts ...call.Option) (*CreateEndpointWaiter, error) { +func (c *internalClient) CreateEndpoint(ctx context.Context, req CreateEndpointRequest, opts ...call.Option) (*CreateEndpointWaiter, error) { resp, err := c.createEndpointBase(ctx, req, opts...) if err != nil { return nil, err @@ -159,13 +159,18 @@ func (c *internalClient) CreateEndpoint(ctx context.Context, req *CreateEndpoint // CreateEndpointWaiter tracks the state of the operation started by CreateEndpoint. type CreateEndpointWaiter struct { - poll func(context.Context, *GetEndpointRequest, ...call.Option) (*Endpoint, error) + poll func(context.Context, GetEndpointRequest, ...call.Option) (*Endpoint, error) name string } +// GetName returns the Name value used to identify the operation. +func (w *CreateEndpointWaiter) GetName() string { + return w.name +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *CreateEndpointWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetEndpointRequest{ + pollResp, err := w.poll(ctx, GetEndpointRequest{ Name: &w.name, }, opts...) if err != nil { @@ -193,7 +198,7 @@ func (w *CreateEndpointWaiter) Done(ctx context.Context, opts ...call.Option) (b func (w *CreateEndpointWaiter) Wait(ctx context.Context, opts ...lro.Option) (*Endpoint, error) { var result *Endpoint poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetEndpointRequest{ + pollResp, err := w.poll(ctx, GetEndpointRequest{ Name: &w.name, }) if err != nil { @@ -230,8 +235,8 @@ func (w *CreateEndpointWaiter) Wait(ctx context.Context, opts ...lro.Option) (*E } // Create a new index. -func (c *internalClient) CreateVectorIndex(ctx context.Context, req *CreateVectorIndexRequest, opts ...call.Option) (*VectorIndex, error) { - wireReq, err := createVectorIndexRequestToWire(req) +func (c *internalClient) CreateVectorIndex(ctx context.Context, req CreateVectorIndexRequest, opts ...call.Option) (*VectorIndex, error) { + wireReq, err := createVectorIndexRequestToWire(&req) if err != nil { return nil, err } @@ -296,8 +301,8 @@ func (c *internalClient) CreateVectorIndex(ctx context.Context, req *CreateVecto } // Handles the deletion of data from a specified vector index. -func (c *internalClient) DeleteDataVectorIndex(ctx context.Context, req *DeleteDataVectorIndexRequest, opts ...call.Option) (*DeleteDataVectorIndexResponse, error) { - wireReq, err := deleteDataVectorIndexRequestToWire(req) +func (c *internalClient) DeleteDataVectorIndex(ctx context.Context, req DeleteDataVectorIndexRequest, opts ...call.Option) (*DeleteDataVectorIndexResponse, error) { + wireReq, err := deleteDataVectorIndexRequestToWire(&req) if err != nil { return nil, err } @@ -314,7 +319,11 @@ func (c *internalClient) DeleteDataVectorIndex(ctx context.Context, req *DeleteD } pb := pathBuilder{} pb.literal("/api/2.0/vector-search/indexes/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/delete-data") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -364,7 +373,7 @@ func (c *internalClient) DeleteDataVectorIndex(ctx context.Context, req *DeleteD } // Delete an AI Search endpoint. -func (c *internalClient) DeleteEndpoint(ctx context.Context, req *DeleteEndpointRequest, opts ...call.Option) (*DeleteEndpointResponse, error) { +func (c *internalClient) DeleteEndpoint(ctx context.Context, req DeleteEndpointRequest, opts ...call.Option) (*DeleteEndpointResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -378,7 +387,11 @@ func (c *internalClient) DeleteEndpoint(ctx context.Context, req *DeleteEndpoint } pb := pathBuilder{} pb.literal("/api/2.0/vector-search/endpoints/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -418,7 +431,7 @@ func (c *internalClient) DeleteEndpoint(ctx context.Context, req *DeleteEndpoint } // Delete an index. -func (c *internalClient) DeleteVectorIndex(ctx context.Context, req *DeleteVectorIndexRequest, opts ...call.Option) (*DeleteVectorIndexResponse, error) { +func (c *internalClient) DeleteVectorIndex(ctx context.Context, req DeleteVectorIndexRequest, opts ...call.Option) (*DeleteVectorIndexResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -432,7 +445,11 @@ func (c *internalClient) DeleteVectorIndex(ctx context.Context, req *DeleteVecto } pb := pathBuilder{} pb.literal("/api/2.0/vector-search/indexes/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -472,7 +489,7 @@ func (c *internalClient) DeleteVectorIndex(ctx context.Context, req *DeleteVecto } // Get details for a single AI Search endpoint. -func (c *internalClient) GetEndpoint(ctx context.Context, req *GetEndpointRequest, opts ...call.Option) (*Endpoint, error) { +func (c *internalClient) GetEndpoint(ctx context.Context, req GetEndpointRequest, opts ...call.Option) (*Endpoint, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -486,7 +503,11 @@ func (c *internalClient) GetEndpoint(ctx context.Context, req *GetEndpointReques } pb := pathBuilder{} pb.literal("/api/2.0/vector-search/endpoints/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -532,8 +553,8 @@ func (c *internalClient) GetEndpoint(ctx context.Context, req *GetEndpointReques } // Get an index. -func (c *internalClient) GetVectorIndex(ctx context.Context, req *GetVectorIndexRequest, opts ...call.Option) (*VectorIndex, error) { - wireReq, err := getVectorIndexRequestToWire(req) +func (c *internalClient) GetVectorIndex(ctx context.Context, req GetVectorIndexRequest, opts ...call.Option) (*VectorIndex, error) { + wireReq, err := getVectorIndexRequestToWire(&req) if err != nil { return nil, err } @@ -550,7 +571,11 @@ func (c *internalClient) GetVectorIndex(ctx context.Context, req *GetVectorIndex } pb := pathBuilder{} pb.literal("/api/2.0/vector-search/indexes/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "ensure_reranker_compatible", wireReq.EnsureRerankerCompatible); err != nil { @@ -599,8 +624,8 @@ func (c *internalClient) GetVectorIndex(ctx context.Context, req *GetVectorIndex } // List all AI Search endpoints in the workspace. -func (c *internalClient) ListEndpoints(ctx context.Context, req *ListEndpointsRequest, opts ...call.Option) (*ListEndpointResponse, error) { - wireReq, err := listEndpointsRequestToWire(req) +func (c *internalClient) ListEndpoints(ctx context.Context, req ListEndpointsRequest, opts ...call.Option) (*ListEndpointResponse, error) { + wireReq, err := listEndpointsRequestToWire(&req) if err != nil { return nil, err } @@ -667,7 +692,7 @@ func (c *internalClient) ListEndpoints(ctx context.Context, req *ListEndpointsRe // // For example: // -// for item, err := range c.ListEndpointsIter(ctx, &ListEndpointsRequest{}) { +// for item, err := range c.ListEndpointsIter(ctx, ListEndpointsRequest{}) { // if err != nil { // return err // } @@ -679,16 +704,13 @@ func (c *internalClient) ListEndpoints(ctx context.Context, req *ListEndpointsRe // // Callers who need custom pagination logic should use // ListEndpoints directly. -func (c *internalClient) ListEndpointsIter(ctx context.Context, req *ListEndpointsRequest, opts ...call.Option) iter.Seq2[*Endpoint, error] { +func (c *internalClient) ListEndpointsIter(ctx context.Context, req ListEndpointsRequest, opts ...call.Option) iter.Seq2[*Endpoint, error] { return func(yield func(*Endpoint, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListEndpointsRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListEndpoints(ctx, &pageReq, opts...) + resp, err := c.ListEndpoints(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -707,8 +729,8 @@ func (c *internalClient) ListEndpointsIter(ctx context.Context, req *ListEndpoin } // List all indexes in the given endpoint. -func (c *internalClient) ListVectorIndex(ctx context.Context, req *ListVectorIndexRequest, opts ...call.Option) (*ListVectorIndexResponse, error) { - wireReq, err := listVectorIndexRequestToWire(req) +func (c *internalClient) ListVectorIndex(ctx context.Context, req ListVectorIndexRequest, opts ...call.Option) (*ListVectorIndexResponse, error) { + wireReq, err := listVectorIndexRequestToWire(&req) if err != nil { return nil, err } @@ -778,7 +800,7 @@ func (c *internalClient) ListVectorIndex(ctx context.Context, req *ListVectorInd // // For example: // -// for item, err := range c.ListVectorIndexIter(ctx, &ListVectorIndexRequest{}) { +// for item, err := range c.ListVectorIndexIter(ctx, ListVectorIndexRequest{}) { // if err != nil { // return err // } @@ -790,16 +812,13 @@ func (c *internalClient) ListVectorIndex(ctx context.Context, req *ListVectorInd // // Callers who need custom pagination logic should use // ListVectorIndex directly. -func (c *internalClient) ListVectorIndexIter(ctx context.Context, req *ListVectorIndexRequest, opts ...call.Option) iter.Seq2[*MiniVectorIndex, error] { +func (c *internalClient) ListVectorIndexIter(ctx context.Context, req ListVectorIndexRequest, opts ...call.Option) iter.Seq2[*MiniVectorIndex, error] { return func(yield func(*MiniVectorIndex, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListVectorIndexRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListVectorIndex(ctx, &pageReq, opts...) + resp, err := c.ListVectorIndex(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -818,8 +837,8 @@ func (c *internalClient) ListVectorIndexIter(ctx context.Context, req *ListVecto } // Update an endpoint -func (c *internalClient) PatchEndpoint(ctx context.Context, req *PatchEndpointRequest, opts ...call.Option) (*Endpoint, error) { - wireReq, err := patchEndpointRequestToWire(req) +func (c *internalClient) PatchEndpoint(ctx context.Context, req PatchEndpointRequest, opts ...call.Option) (*Endpoint, error) { + wireReq, err := patchEndpointRequestToWire(&req) if err != nil { return nil, err } @@ -840,7 +859,11 @@ func (c *internalClient) PatchEndpoint(ctx context.Context, req *PatchEndpointRe } pb := pathBuilder{} pb.literal("/api/2.0/vector-search/endpoints/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -887,8 +910,8 @@ func (c *internalClient) PatchEndpoint(ctx context.Context, req *PatchEndpointRe } // Update the budget policy of an endpoint -func (c *internalClient) PatchEndpointBudgetPolicy(ctx context.Context, req *PatchEndpointBudgetPolicyRequest, opts ...call.Option) (*PatchEndpointBudgetPolicyResponse, error) { - wireReq, err := patchEndpointBudgetPolicyRequestToWire(req) +func (c *internalClient) PatchEndpointBudgetPolicy(ctx context.Context, req PatchEndpointBudgetPolicyRequest, opts ...call.Option) (*PatchEndpointBudgetPolicyResponse, error) { + wireReq, err := patchEndpointBudgetPolicyRequestToWire(&req) if err != nil { return nil, err } @@ -909,7 +932,11 @@ func (c *internalClient) PatchEndpointBudgetPolicy(ctx context.Context, req *Pat } pb := pathBuilder{} pb.literal("/api/2.0/vector-search/endpoints/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/budget-policy") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -957,8 +984,8 @@ func (c *internalClient) PatchEndpointBudgetPolicy(ctx context.Context, req *Pat } // Query the specified vector index. -func (c *internalClient) QueryVectorIndex(ctx context.Context, req *QueryVectorIndexRequest, opts ...call.Option) (*QueryVectorIndexResponse, error) { - wireReq, err := queryVectorIndexRequestToWire(req) +func (c *internalClient) QueryVectorIndex(ctx context.Context, req QueryVectorIndexRequest, opts ...call.Option) (*QueryVectorIndexResponse, error) { + wireReq, err := queryVectorIndexRequestToWire(&req) if err != nil { return nil, err } @@ -979,7 +1006,11 @@ func (c *internalClient) QueryVectorIndex(ctx context.Context, req *QueryVectorI } pb := pathBuilder{} pb.literal("/api/2.0/vector-search/indexes/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/query") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1028,8 +1059,8 @@ func (c *internalClient) QueryVectorIndex(ctx context.Context, req *QueryVectorI // Use `next_page_token` returned from previous `QueryVectorIndex` or // `QueryVectorIndexNextPage` request to fetch next page of results. -func (c *internalClient) QueryVectorIndexNextPage(ctx context.Context, req *QueryVectorIndexNextPageRequest, opts ...call.Option) (*QueryVectorIndexResponse, error) { - wireReq, err := queryVectorIndexNextPageRequestToWire(req) +func (c *internalClient) QueryVectorIndexNextPage(ctx context.Context, req QueryVectorIndexNextPageRequest, opts ...call.Option) (*QueryVectorIndexResponse, error) { + wireReq, err := queryVectorIndexNextPageRequestToWire(&req) if err != nil { return nil, err } @@ -1050,7 +1081,11 @@ func (c *internalClient) QueryVectorIndexNextPage(ctx context.Context, req *Quer } pb := pathBuilder{} pb.literal("/api/2.0/vector-search/indexes/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/query-next-page") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1098,8 +1133,8 @@ func (c *internalClient) QueryVectorIndexNextPage(ctx context.Context, req *Quer } // Retrieve user-visible metrics for an endpoint -func (c *internalClient) RetrieveUserVisibleMetrics(ctx context.Context, req *RetrieveUserVisibleMetricsRequest, opts ...call.Option) (*RetrieveUserVisibleMetricsResponse, error) { - wireReq, err := retrieveUserVisibleMetricsRequestToWire(req) +func (c *internalClient) RetrieveUserVisibleMetrics(ctx context.Context, req RetrieveUserVisibleMetricsRequest, opts ...call.Option) (*RetrieveUserVisibleMetricsResponse, error) { + wireReq, err := retrieveUserVisibleMetricsRequestToWire(&req) if err != nil { return nil, err } @@ -1120,7 +1155,11 @@ func (c *internalClient) RetrieveUserVisibleMetrics(ctx context.Context, req *Re } pb := pathBuilder{} pb.literal("/api/2.0/vector-search/endpoints/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/metrics") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1169,8 +1208,8 @@ func (c *internalClient) RetrieveUserVisibleMetrics(ctx context.Context, req *Re // Scan the specified vector index and return the first `num_results` entries // after the exclusive `primary_key`. -func (c *internalClient) ScanVectorIndex(ctx context.Context, req *ScanVectorIndexRequest, opts ...call.Option) (*ScanVectorIndexResponse, error) { - wireReq, err := scanVectorIndexRequestToWire(req) +func (c *internalClient) ScanVectorIndex(ctx context.Context, req ScanVectorIndexRequest, opts ...call.Option) (*ScanVectorIndexResponse, error) { + wireReq, err := scanVectorIndexRequestToWire(&req) if err != nil { return nil, err } @@ -1191,7 +1230,11 @@ func (c *internalClient) ScanVectorIndex(ctx context.Context, req *ScanVectorInd } pb := pathBuilder{} pb.literal("/api/2.0/vector-search/indexes/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/scan") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1239,8 +1282,8 @@ func (c *internalClient) ScanVectorIndex(ctx context.Context, req *ScanVectorInd } // Triggers a synchronization process for a specified vector index. -func (c *internalClient) SyncVectorIndex(ctx context.Context, req *SyncVectorIndexRequest, opts ...call.Option) (*SyncVectorIndexResponse, error) { - wireReq, err := syncVectorIndexRequestToWire(req) +func (c *internalClient) SyncVectorIndex(ctx context.Context, req SyncVectorIndexRequest, opts ...call.Option) (*SyncVectorIndexResponse, error) { + wireReq, err := syncVectorIndexRequestToWire(&req) if err != nil { return nil, err } @@ -1261,7 +1304,11 @@ func (c *internalClient) SyncVectorIndex(ctx context.Context, req *SyncVectorInd } pb := pathBuilder{} pb.literal("/api/2.0/vector-search/indexes/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/sync") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1303,8 +1350,8 @@ func (c *internalClient) SyncVectorIndex(ctx context.Context, req *SyncVectorInd } // Update the custom tags of an endpoint. -func (c *internalClient) UpdateEndpointCustomTags(ctx context.Context, req *UpdateEndpointCustomTagsRequest, opts ...call.Option) (*UpdateEndpointCustomTagsResponse, error) { - wireReq, err := updateEndpointCustomTagsRequestToWire(req) +func (c *internalClient) UpdateEndpointCustomTags(ctx context.Context, req UpdateEndpointCustomTagsRequest, opts ...call.Option) (*UpdateEndpointCustomTagsResponse, error) { + wireReq, err := updateEndpointCustomTagsRequestToWire(&req) if err != nil { return nil, err } @@ -1325,7 +1372,11 @@ func (c *internalClient) UpdateEndpointCustomTags(ctx context.Context, req *Upda } pb := pathBuilder{} pb.literal("/api/2.0/vector-search/endpoints/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/tags") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1373,8 +1424,8 @@ func (c *internalClient) UpdateEndpointCustomTags(ctx context.Context, req *Upda } // Handles the upserting of data into a specified vector index. -func (c *internalClient) UpsertDataVectorIndex(ctx context.Context, req *UpsertDataVectorIndexRequest, opts ...call.Option) (*UpsertDataVectorIndexResponse, error) { - wireReq, err := upsertDataVectorIndexRequestToWire(req) +func (c *internalClient) UpsertDataVectorIndex(ctx context.Context, req UpsertDataVectorIndexRequest, opts ...call.Option) (*UpsertDataVectorIndexResponse, error) { + wireReq, err := upsertDataVectorIndexRequestToWire(&req) if err != nil { return nil, err } @@ -1395,7 +1446,11 @@ func (c *internalClient) UpsertDataVectorIndex(ctx context.Context, req *UpsertD } pb := pathBuilder{} pb.literal("/api/2.0/vector-search/indexes/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } pb.literal("/upsert-data") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} diff --git a/vectorsearch/v1/genhelper.go b/vectorsearch/v1/genhelper.go old mode 100755 new mode 100644 index db6b94f..a74d6cd --- a/vectorsearch/v1/genhelper.go +++ b/vectorsearch/v1/genhelper.go @@ -199,11 +199,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -216,13 +217,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/vectorsearch/v1/wire.go b/vectorsearch/v1/wire.go old mode 100755 new mode 100644 index 125d5dd..510e0d1 --- a/vectorsearch/v1/wire.go +++ b/vectorsearch/v1/wire.go @@ -3,12 +3,57 @@ package vectorsearch import ( + "bytes" "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + type columnInfoWire struct { Name *string `json:"name,omitempty"` TypeText *string `json:"type_text,omitempty"` @@ -29,19 +74,23 @@ type createEndpointRequestWire struct { EndpointType EndpointType `json:"endpoint_type,omitempty"` BudgetPolicyId *string `json:"budget_policy_id,omitempty"` UsagePolicyId *string `json:"usage_policy_id,omitempty"` - TargetQps *int64 `json:"target_qps,omitempty"` + TargetQps *wireInt64 `json:"target_qps,omitempty"` } func createEndpointRequestToWire(v *CreateEndpointRequest) (*createEndpointRequestWire, error) { if v == nil { return nil, nil } + targetQpsWireValue, err := int64ToWire(v.TargetQps) + if err != nil { + return nil, fmt.Errorf("%s: %w", "CreateEndpointRequest.TargetQps", err) + } return &createEndpointRequestWire{ Name: v.Name, EndpointType: v.EndpointType, BudgetPolicyId: v.BudgetPolicyId, UsagePolicyId: v.UsagePolicyId, - TargetQps: v.TargetQps, + TargetQps: targetQpsWireValue, }, nil } @@ -344,8 +393,8 @@ func embeddingVectorColumnFromWire(w *embeddingVectorColumnWire) (*EmbeddingVect type endpointWire struct { Name *string `json:"name,omitempty"` Creator *string `json:"creator,omitempty"` - CreationTimestamp *int64 `json:"creation_timestamp,omitempty"` - LastUpdatedTimestamp *int64 `json:"last_updated_timestamp,omitempty"` + CreationTimestamp *wireInt64 `json:"creation_timestamp,omitempty"` + LastUpdatedTimestamp *wireInt64 `json:"last_updated_timestamp,omitempty"` EndpointType EndpointType `json:"endpoint_type,omitempty"` LastUpdatedUser *string `json:"last_updated_user,omitempty"` Id *string `json:"id,omitempty"` @@ -361,6 +410,14 @@ func endpointFromWire(w *endpointWire) (*Endpoint, error) { if w == nil { return nil, nil } + creationTimestampPublicValue, err := int64FromWire(w.CreationTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Endpoint.CreationTimestamp", err) + } + lastUpdatedTimestampPublicValue, err := int64FromWire(w.LastUpdatedTimestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Endpoint.LastUpdatedTimestamp", err) + } endpointStatusPublicValue, err := endpointStatusFromWire(w.EndpointStatus) if err != nil { return nil, fmt.Errorf("%s: %w", "Endpoint.EndpointStatus", err) @@ -376,8 +433,8 @@ func endpointFromWire(w *endpointWire) (*Endpoint, error) { return &Endpoint{ Name: w.Name, Creator: w.Creator, - CreationTimestamp: w.CreationTimestamp, - LastUpdatedTimestamp: w.LastUpdatedTimestamp, + CreationTimestamp: creationTimestampPublicValue, + LastUpdatedTimestamp: lastUpdatedTimestampPublicValue, EndpointType: w.EndpointType, LastUpdatedUser: w.LastUpdatedUser, Id: w.Id, @@ -392,16 +449,20 @@ func endpointFromWire(w *endpointWire) (*Endpoint, error) { type endpointScalingInfoWire struct { State ScalingChangeState `json:"state,omitempty"` - RequestedTargetQps *int64 `json:"requested_target_qps,omitempty"` + RequestedTargetQps *wireInt64 `json:"requested_target_qps,omitempty"` } func endpointScalingInfoFromWire(w *endpointScalingInfoWire) (*EndpointScalingInfo, error) { if w == nil { return nil, nil } + requestedTargetQpsPublicValue, err := int64FromWire(w.RequestedTargetQps) + if err != nil { + return nil, fmt.Errorf("%s: %w", "EndpointScalingInfo.RequestedTargetQps", err) + } return &EndpointScalingInfo{ State: w.State, - RequestedTargetQps: w.RequestedTargetQps, + RequestedTargetQps: requestedTargetQpsPublicValue, }, nil } @@ -614,16 +675,20 @@ func metricLabelFromWire(w *metricLabelWire) (*MetricLabel, error) { } type metricValueWire struct { - Timestamp *int64 `json:"timestamp,omitempty"` - Value *float64 `json:"value,omitempty"` + Timestamp *wireInt64 `json:"timestamp,omitempty"` + Value *float64 `json:"value,omitempty"` } func metricValueFromWire(w *metricValueWire) (*MetricValue, error) { if w == nil { return nil, nil } + timestampPublicValue, err := int64FromWire(w.Timestamp) + if err != nil { + return nil, fmt.Errorf("%s: %w", "MetricValue.Timestamp", err) + } return &MetricValue{ - Timestamp: w.Timestamp, + Timestamp: timestampPublicValue, Value: w.Value, }, nil } @@ -741,17 +806,21 @@ func patchEndpointBudgetPolicyResponseFromWire(w *patchEndpointBudgetPolicyRespo } type patchEndpointRequestWire struct { - Name *string `json:"name,omitempty"` - TargetQps *int64 `json:"target_qps,omitempty"` + Name *string `json:"name,omitempty"` + TargetQps *wireInt64 `json:"target_qps,omitempty"` } func patchEndpointRequestToWire(v *PatchEndpointRequest) (*patchEndpointRequestWire, error) { if v == nil { return nil, nil } + targetQpsWireValue, err := int64ToWire(v.TargetQps) + if err != nil { + return nil, fmt.Errorf("%s: %w", "PatchEndpointRequest.TargetQps", err) + } return &patchEndpointRequestWire{ Name: v.Name, - TargetQps: v.TargetQps, + TargetQps: targetQpsWireValue, }, nil } @@ -1103,16 +1172,20 @@ func upsertDataVectorIndexResponseFromWire(w *upsertDataVectorIndexResponseWire) } type upsertDeleteDataResultWire struct { - SuccessRowCount *int64 `json:"success_row_count,omitempty"` - FailedPrimaryKeys []string `json:"failed_primary_keys,omitempty"` + SuccessRowCount *wireInt64 `json:"success_row_count,omitempty"` + FailedPrimaryKeys []string `json:"failed_primary_keys,omitempty"` } func upsertDeleteDataResultFromWire(w *upsertDeleteDataResultWire) (*UpsertDeleteDataResult, error) { if w == nil { return nil, nil } + successRowCountPublicValue, err := int64FromWire(w.SuccessRowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "UpsertDeleteDataResult.SuccessRowCount", err) + } return &UpsertDeleteDataResult{ - SuccessRowCount: w.SuccessRowCount, + SuccessRowCount: successRowCountPublicValue, FailedPrimaryKeys: w.FailedPrimaryKeys, }, nil } @@ -1234,19 +1307,23 @@ func vectorIndexFromWire(w *vectorIndexWire) (*VectorIndex, error) { } type vectorIndexStatusWire struct { - Message *string `json:"message,omitempty"` - IndexedRowCount *int64 `json:"indexed_row_count,omitempty"` - Ready *bool `json:"ready,omitempty"` - IndexUrl *string `json:"index_url,omitempty"` + Message *string `json:"message,omitempty"` + IndexedRowCount *wireInt64 `json:"indexed_row_count,omitempty"` + Ready *bool `json:"ready,omitempty"` + IndexUrl *string `json:"index_url,omitempty"` } func vectorIndexStatusFromWire(w *vectorIndexStatusWire) (*VectorIndexStatus, error) { if w == nil { return nil, nil } + indexedRowCountPublicValue, err := int64FromWire(w.IndexedRowCount) + if err != nil { + return nil, fmt.Errorf("%s: %w", "VectorIndexStatus.IndexedRowCount", err) + } return &VectorIndexStatus{ Message: w.Message, - IndexedRowCount: w.IndexedRowCount, + IndexedRowCount: indexedRowCountPublicValue, Ready: w.Ready, IndexUrl: w.IndexUrl, }, nil diff --git a/warehouses/CHANGELOG.md b/warehouses/CHANGELOG.md index 6224c04..19f237c 100644 --- a/warehouses/CHANGELOG.md +++ b/warehouses/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/warehouses/go.mod b/warehouses/go.mod index 1f48161..2f35a07 100644 --- a/warehouses/go.mod +++ b/warehouses/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/warehouses/internal/version.go b/warehouses/internal/version.go index f1b7501..39585bb 100644 --- a/warehouses/internal/version.go +++ b/warehouses/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-warehouses" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/warehouses/v1/client.go b/warehouses/v1/client.go old mode 100755 new mode 100644 index d9faf92..4038c9f --- a/warehouses/v1/client.go +++ b/warehouses/v1/client.go @@ -78,8 +78,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // Creates a new default warehouse override for a user. Users can create their // own override. Admins can create overrides for any user. -func (c *internalClient) CreateDefaultWarehouseOverride(ctx context.Context, req *CreateDefaultWarehouseOverrideRequest, opts ...call.Option) (*DefaultWarehouseOverride, error) { - wireReq, err := createDefaultWarehouseOverrideRequestToWire(req) +func (c *internalClient) CreateDefaultWarehouseOverride(ctx context.Context, req CreateDefaultWarehouseOverrideRequest, opts ...call.Option) (*DefaultWarehouseOverride, error) { + wireReq, err := createDefaultWarehouseOverrideRequestToWire(&req) if err != nil { return nil, err } @@ -147,8 +147,8 @@ func (c *internalClient) CreateDefaultWarehouseOverride(ctx context.Context, req } // Creates a new SQL warehouse. -func (c *internalClient) createWarehouseBase(ctx context.Context, req *CreateWarehouseRequest, opts ...call.Option) (*CreateWarehouseResponse, error) { - wireReq, err := createWarehouseRequestToWire(req) +func (c *internalClient) createWarehouseBase(ctx context.Context, req CreateWarehouseRequest, opts ...call.Option) (*CreateWarehouseResponse, error) { + wireReq, err := createWarehouseRequestToWire(&req) if err != nil { return nil, err } @@ -213,7 +213,7 @@ func (c *internalClient) createWarehouseBase(ctx context.Context, req *CreateWar } // Creates a new SQL warehouse. -func (c *internalClient) CreateWarehouse(ctx context.Context, req *CreateWarehouseRequest, opts ...call.Option) (*CreateWarehouseWaiter, error) { +func (c *internalClient) CreateWarehouse(ctx context.Context, req CreateWarehouseRequest, opts ...call.Option) (*CreateWarehouseWaiter, error) { resp, err := c.createWarehouseBase(ctx, req, opts...) if err != nil { return nil, err @@ -229,13 +229,18 @@ func (c *internalClient) CreateWarehouse(ctx context.Context, req *CreateWarehou // CreateWarehouseWaiter tracks the state of the operation started by CreateWarehouse. type CreateWarehouseWaiter struct { - poll func(context.Context, *GetWarehouseRequest, ...call.Option) (*GetWarehouseResponse, error) + poll func(context.Context, GetWarehouseRequest, ...call.Option) (*GetWarehouseResponse, error) id string } +// GetId returns the Id value used to identify the operation. +func (w *CreateWarehouseWaiter) GetId() string { + return w.id +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *CreateWarehouseWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetWarehouseRequest{ + pollResp, err := w.poll(ctx, GetWarehouseRequest{ Id: &w.id, }, opts...) if err != nil { @@ -260,7 +265,7 @@ func (w *CreateWarehouseWaiter) Done(ctx context.Context, opts ...call.Option) ( func (w *CreateWarehouseWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GetWarehouseResponse, error) { var result *GetWarehouseResponse poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetWarehouseRequest{ + pollResp, err := w.poll(ctx, GetWarehouseRequest{ Id: &w.id, }) if err != nil { @@ -296,7 +301,7 @@ func (w *CreateWarehouseWaiter) Wait(ctx context.Context, opts ...lro.Option) (* // Deletes the default warehouse override for a user. Users can delete their own // override. Admins can delete overrides for any user. After deletion, the // workspace default warehouse will be used. -func (c *internalClient) DeleteDefaultWarehouseOverride(ctx context.Context, req *DeleteDefaultWarehouseOverrideRequest, opts ...call.Option) error { +func (c *internalClient) DeleteDefaultWarehouseOverride(ctx context.Context, req DeleteDefaultWarehouseOverrideRequest, opts ...call.Option) error { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -310,7 +315,11 @@ func (c *internalClient) DeleteDefaultWarehouseOverride(ctx context.Context, req } pb := pathBuilder{} pb.literal("/api/warehouses/v1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -347,7 +356,7 @@ func (c *internalClient) DeleteDefaultWarehouseOverride(ctx context.Context, req } // Deletes a SQL warehouse. -func (c *internalClient) DeleteWarehouse(ctx context.Context, req *DeleteWarehouseRequest, opts ...call.Option) (*DeleteWarehouseResponse, error) { +func (c *internalClient) DeleteWarehouse(ctx context.Context, req DeleteWarehouseRequest, opts ...call.Option) (*DeleteWarehouseResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -361,7 +370,11 @@ func (c *internalClient) DeleteWarehouse(ctx context.Context, req *DeleteWarehou } pb := pathBuilder{} pb.literal("/api/2.0/sql/warehouses/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -401,8 +414,8 @@ func (c *internalClient) DeleteWarehouse(ctx context.Context, req *DeleteWarehou } // Updates the configuration for a SQL warehouse. -func (c *internalClient) editWarehouseBase(ctx context.Context, req *EditWarehouseRequest, opts ...call.Option) (*EditWarehouseResponse, error) { - wireReq, err := editWarehouseRequestToWire(req) +func (c *internalClient) editWarehouseBase(ctx context.Context, req EditWarehouseRequest, opts ...call.Option) (*EditWarehouseResponse, error) { + wireReq, err := editWarehouseRequestToWire(&req) if err != nil { return nil, err } @@ -423,7 +436,11 @@ func (c *internalClient) editWarehouseBase(ctx context.Context, req *EditWarehou } pb := pathBuilder{} pb.literal("/api/2.0/sql/warehouses/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } pb.literal("/edit") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -465,7 +482,7 @@ func (c *internalClient) editWarehouseBase(ctx context.Context, req *EditWarehou } // Updates the configuration for a SQL warehouse. -func (c *internalClient) EditWarehouse(ctx context.Context, req *EditWarehouseRequest, opts ...call.Option) (*EditWarehouseWaiter, error) { +func (c *internalClient) EditWarehouse(ctx context.Context, req EditWarehouseRequest, opts ...call.Option) (*EditWarehouseWaiter, error) { if req.Id == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "Id") } @@ -482,13 +499,18 @@ func (c *internalClient) EditWarehouse(ctx context.Context, req *EditWarehouseRe // EditWarehouseWaiter tracks the state of the operation started by EditWarehouse. type EditWarehouseWaiter struct { - poll func(context.Context, *GetWarehouseRequest, ...call.Option) (*GetWarehouseResponse, error) + poll func(context.Context, GetWarehouseRequest, ...call.Option) (*GetWarehouseResponse, error) id string } +// GetId returns the Id value used to identify the operation. +func (w *EditWarehouseWaiter) GetId() string { + return w.id +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *EditWarehouseWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetWarehouseRequest{ + pollResp, err := w.poll(ctx, GetWarehouseRequest{ Id: &w.id, }, opts...) if err != nil { @@ -513,7 +535,7 @@ func (w *EditWarehouseWaiter) Done(ctx context.Context, opts ...call.Option) (bo func (w *EditWarehouseWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GetWarehouseResponse, error) { var result *GetWarehouseResponse poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetWarehouseRequest{ + pollResp, err := w.poll(ctx, GetWarehouseRequest{ Id: &w.id, }) if err != nil { @@ -549,7 +571,7 @@ func (w *EditWarehouseWaiter) Wait(ctx context.Context, opts ...lro.Option) (*Ge // Returns the default warehouse override for a user. Users can fetch their own // override. Admins can fetch overrides for any user. If no override exists, the // UI will fallback to the workspace default warehouse. -func (c *internalClient) GetDefaultWarehouseOverride(ctx context.Context, req *GetDefaultWarehouseOverrideRequest, opts ...call.Option) (*DefaultWarehouseOverride, error) { +func (c *internalClient) GetDefaultWarehouseOverride(ctx context.Context, req GetDefaultWarehouseOverrideRequest, opts ...call.Option) (*DefaultWarehouseOverride, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -563,7 +585,11 @@ func (c *internalClient) GetDefaultWarehouseOverride(ctx context.Context, req *G } pb := pathBuilder{} pb.literal("/api/warehouses/v1/") - pb.singleSegment(*req.Name) + if req.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -609,7 +635,7 @@ func (c *internalClient) GetDefaultWarehouseOverride(ctx context.Context, req *G } // Gets the information for a single SQL warehouse. -func (c *internalClient) GetWarehouse(ctx context.Context, req *GetWarehouseRequest, opts ...call.Option) (*GetWarehouseResponse, error) { +func (c *internalClient) GetWarehouse(ctx context.Context, req GetWarehouseRequest, opts ...call.Option) (*GetWarehouseResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -623,7 +649,11 @@ func (c *internalClient) GetWarehouse(ctx context.Context, req *GetWarehouseRequ } pb := pathBuilder{} pb.literal("/api/2.0/sql/warehouses/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -670,7 +700,7 @@ func (c *internalClient) GetWarehouse(ctx context.Context, req *GetWarehouseRequ // Gets the workspace level configuration that is shared by all SQL warehouses // in a workspace. -func (c *internalClient) GetWorkspaceWarehouseConfig(ctx context.Context, req *GetWorkspaceWarehouseConfigRequest, opts ...call.Option) (*GetWorkspaceWarehouseConfigResponse, error) { +func (c *internalClient) GetWorkspaceWarehouseConfig(ctx context.Context, req GetWorkspaceWarehouseConfigRequest, opts ...call.Option) (*GetWorkspaceWarehouseConfigResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -728,8 +758,8 @@ func (c *internalClient) GetWorkspaceWarehouseConfig(ctx context.Context, req *G // Lists all default warehouse overrides in the workspace. Only workspace // administrators can list all overrides. -func (c *internalClient) ListDefaultWarehouseOverrides(ctx context.Context, req *ListDefaultWarehouseOverridesRequest, opts ...call.Option) (*ListDefaultWarehouseOverridesResponse, error) { - wireReq, err := listDefaultWarehouseOverridesRequestToWire(req) +func (c *internalClient) ListDefaultWarehouseOverrides(ctx context.Context, req ListDefaultWarehouseOverridesRequest, opts ...call.Option) (*ListDefaultWarehouseOverridesResponse, error) { + wireReq, err := listDefaultWarehouseOverridesRequestToWire(&req) if err != nil { return nil, err } @@ -799,7 +829,7 @@ func (c *internalClient) ListDefaultWarehouseOverrides(ctx context.Context, req // // For example: // -// for item, err := range c.ListDefaultWarehouseOverridesIter(ctx, &ListDefaultWarehouseOverridesRequest{}) { +// for item, err := range c.ListDefaultWarehouseOverridesIter(ctx, ListDefaultWarehouseOverridesRequest{}) { // if err != nil { // return err // } @@ -811,16 +841,13 @@ func (c *internalClient) ListDefaultWarehouseOverrides(ctx context.Context, req // // Callers who need custom pagination logic should use // ListDefaultWarehouseOverrides directly. -func (c *internalClient) ListDefaultWarehouseOverridesIter(ctx context.Context, req *ListDefaultWarehouseOverridesRequest, opts ...call.Option) iter.Seq2[*DefaultWarehouseOverride, error] { +func (c *internalClient) ListDefaultWarehouseOverridesIter(ctx context.Context, req ListDefaultWarehouseOverridesRequest, opts ...call.Option) iter.Seq2[*DefaultWarehouseOverride, error] { return func(yield func(*DefaultWarehouseOverride, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListDefaultWarehouseOverridesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListDefaultWarehouseOverrides(ctx, &pageReq, opts...) + resp, err := c.ListDefaultWarehouseOverrides(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -839,8 +866,8 @@ func (c *internalClient) ListDefaultWarehouseOverridesIter(ctx context.Context, } // Lists all SQL warehouses that a user has access to. -func (c *internalClient) ListWarehouses(ctx context.Context, req *ListWarehousesRequest, opts ...call.Option) (*ListWarehousesResponse, error) { - wireReq, err := listWarehousesRequestToWire(req) +func (c *internalClient) ListWarehouses(ctx context.Context, req ListWarehousesRequest, opts ...call.Option) (*ListWarehousesResponse, error) { + wireReq, err := listWarehousesRequestToWire(&req) if err != nil { return nil, err } @@ -913,7 +940,7 @@ func (c *internalClient) ListWarehouses(ctx context.Context, req *ListWarehouses // // For example: // -// for item, err := range c.ListWarehousesIter(ctx, &ListWarehousesRequest{}) { +// for item, err := range c.ListWarehousesIter(ctx, ListWarehousesRequest{}) { // if err != nil { // return err // } @@ -925,16 +952,13 @@ func (c *internalClient) ListWarehouses(ctx context.Context, req *ListWarehouses // // Callers who need custom pagination logic should use // ListWarehouses directly. -func (c *internalClient) ListWarehousesIter(ctx context.Context, req *ListWarehousesRequest, opts ...call.Option) iter.Seq2[*EndpointInfo, error] { +func (c *internalClient) ListWarehousesIter(ctx context.Context, req ListWarehousesRequest, opts ...call.Option) iter.Seq2[*EndpointInfo, error] { return func(yield func(*EndpointInfo, error) bool) { - // Copy the request so advancing the pagination field does not mutate the - // caller's struct. Other reference-bearing fields are shared and must remain read-only. - pageReq := ListWarehousesRequest{} - if req != nil { - pageReq = *req - } + // Keep pagination state local to this traversal so reusing the iterator starts + // from the original request. Reference-bearing fields remain shared and read-only. + pageReq := req for { - resp, err := c.ListWarehouses(ctx, &pageReq, opts...) + resp, err := c.ListWarehouses(ctx, pageReq, opts...) if err != nil { yield(nil, err) return @@ -954,8 +978,8 @@ func (c *internalClient) ListWarehousesIter(ctx context.Context, req *ListWareho // Sets the workspace level configuration that is shared by all SQL warehouses // in a workspace. -func (c *internalClient) SetWorkspaceWarehouseConfig(ctx context.Context, req *SetWorkspaceWarehouseConfigRequest, opts ...call.Option) (*SetWorkspaceWarehouseConfigResponse, error) { - wireReq, err := setWorkspaceWarehouseConfigRequestToWire(req) +func (c *internalClient) SetWorkspaceWarehouseConfig(ctx context.Context, req SetWorkspaceWarehouseConfigRequest, opts ...call.Option) (*SetWorkspaceWarehouseConfigResponse, error) { + wireReq, err := setWorkspaceWarehouseConfigRequestToWire(&req) if err != nil { return nil, err } @@ -1014,8 +1038,8 @@ func (c *internalClient) SetWorkspaceWarehouseConfig(ctx context.Context, req *S } // Starts a SQL warehouse. -func (c *internalClient) startWarehouseBase(ctx context.Context, req *StartRequest, opts ...call.Option) (*StartResponse, error) { - wireReq, err := startRequestToWire(req) +func (c *internalClient) startWarehouseBase(ctx context.Context, req StartRequest, opts ...call.Option) (*StartResponse, error) { + wireReq, err := startRequestToWire(&req) if err != nil { return nil, err } @@ -1036,7 +1060,11 @@ func (c *internalClient) startWarehouseBase(ctx context.Context, req *StartReque } pb := pathBuilder{} pb.literal("/api/2.0/sql/warehouses/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } pb.literal("/start") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1078,7 +1106,7 @@ func (c *internalClient) startWarehouseBase(ctx context.Context, req *StartReque } // Starts a SQL warehouse. -func (c *internalClient) StartWarehouse(ctx context.Context, req *StartRequest, opts ...call.Option) (*StartWarehouseWaiter, error) { +func (c *internalClient) StartWarehouse(ctx context.Context, req StartRequest, opts ...call.Option) (*StartWarehouseWaiter, error) { if req.Id == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "Id") } @@ -1095,13 +1123,18 @@ func (c *internalClient) StartWarehouse(ctx context.Context, req *StartRequest, // StartWarehouseWaiter tracks the state of the operation started by StartWarehouse. type StartWarehouseWaiter struct { - poll func(context.Context, *GetWarehouseRequest, ...call.Option) (*GetWarehouseResponse, error) + poll func(context.Context, GetWarehouseRequest, ...call.Option) (*GetWarehouseResponse, error) id string } +// GetId returns the Id value used to identify the operation. +func (w *StartWarehouseWaiter) GetId() string { + return w.id +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *StartWarehouseWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetWarehouseRequest{ + pollResp, err := w.poll(ctx, GetWarehouseRequest{ Id: &w.id, }, opts...) if err != nil { @@ -1126,7 +1159,7 @@ func (w *StartWarehouseWaiter) Done(ctx context.Context, opts ...call.Option) (b func (w *StartWarehouseWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GetWarehouseResponse, error) { var result *GetWarehouseResponse poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetWarehouseRequest{ + pollResp, err := w.poll(ctx, GetWarehouseRequest{ Id: &w.id, }) if err != nil { @@ -1160,8 +1193,8 @@ func (w *StartWarehouseWaiter) Wait(ctx context.Context, opts ...lro.Option) (*G } // Stops a SQL warehouse. -func (c *internalClient) stopWarehouseBase(ctx context.Context, req *StopRequest, opts ...call.Option) (*StopResponse, error) { - wireReq, err := stopRequestToWire(req) +func (c *internalClient) stopWarehouseBase(ctx context.Context, req StopRequest, opts ...call.Option) (*StopResponse, error) { + wireReq, err := stopRequestToWire(&req) if err != nil { return nil, err } @@ -1182,7 +1215,11 @@ func (c *internalClient) stopWarehouseBase(ctx context.Context, req *StopRequest } pb := pathBuilder{} pb.literal("/api/2.0/sql/warehouses/") - pb.singleSegment(*req.Id) + if req.Id == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.Id) + } pb.literal("/stop") baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} @@ -1224,7 +1261,7 @@ func (c *internalClient) stopWarehouseBase(ctx context.Context, req *StopRequest } // Stops a SQL warehouse. -func (c *internalClient) StopWarehouse(ctx context.Context, req *StopRequest, opts ...call.Option) (*StopWarehouseWaiter, error) { +func (c *internalClient) StopWarehouse(ctx context.Context, req StopRequest, opts ...call.Option) (*StopWarehouseWaiter, error) { if req.Id == nil { return nil, fmt.Errorf("request field %q required for polling is missing", "Id") } @@ -1241,13 +1278,18 @@ func (c *internalClient) StopWarehouse(ctx context.Context, req *StopRequest, op // StopWarehouseWaiter tracks the state of the operation started by StopWarehouse. type StopWarehouseWaiter struct { - poll func(context.Context, *GetWarehouseRequest, ...call.Option) (*GetWarehouseResponse, error) + poll func(context.Context, GetWarehouseRequest, ...call.Option) (*GetWarehouseResponse, error) id string } +// GetId returns the Id value used to identify the operation. +func (w *StopWarehouseWaiter) GetId() string { + return w.id +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *StopWarehouseWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetWarehouseRequest{ + pollResp, err := w.poll(ctx, GetWarehouseRequest{ Id: &w.id, }, opts...) if err != nil { @@ -1272,7 +1314,7 @@ func (w *StopWarehouseWaiter) Done(ctx context.Context, opts ...call.Option) (bo func (w *StopWarehouseWaiter) Wait(ctx context.Context, opts ...lro.Option) (*GetWarehouseResponse, error) { var result *GetWarehouseResponse poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetWarehouseRequest{ + pollResp, err := w.poll(ctx, GetWarehouseRequest{ Id: &w.id, }) if err != nil { @@ -1301,8 +1343,8 @@ func (w *StopWarehouseWaiter) Wait(ctx context.Context, opts ...lro.Option) (*Ge // Updates an existing default warehouse override for a user. Users can update // their own override. Admins can update overrides for any user. -func (c *internalClient) UpdateDefaultWarehouseOverride(ctx context.Context, req *UpdateDefaultWarehouseOverrideRequest, opts ...call.Option) (*DefaultWarehouseOverride, error) { - wireReq, err := updateDefaultWarehouseOverrideRequestToWire(req) +func (c *internalClient) UpdateDefaultWarehouseOverride(ctx context.Context, req UpdateDefaultWarehouseOverrideRequest, opts ...call.Option) (*DefaultWarehouseOverride, error) { + wireReq, err := updateDefaultWarehouseOverrideRequestToWire(&req) if err != nil { return nil, err } @@ -1323,7 +1365,11 @@ func (c *internalClient) UpdateDefaultWarehouseOverride(ctx context.Context, req } pb := pathBuilder{} pb.literal("/api/warehouses/v1/") - pb.singleSegment(*req.DefaultWarehouseOverride.Name) + if req.DefaultWarehouseOverride == nil || req.DefaultWarehouseOverride.Name == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.DefaultWarehouseOverride.Name) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { diff --git a/warehouses/v1/genhelper.go b/warehouses/v1/genhelper.go old mode 100755 new mode 100644 index 2b74409..8455e91 --- a/warehouses/v1/genhelper.go +++ b/warehouses/v1/genhelper.go @@ -199,11 +199,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -216,13 +217,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/warehouses/v1/wire.go b/warehouses/v1/wire.go old mode 100755 new mode 100644 index 7d4d7d5..67e2b41 --- a/warehouses/v1/wire.go +++ b/warehouses/v1/wire.go @@ -3,11 +3,57 @@ package warehouses import ( + "bytes" + "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + func fieldMaskToWire[T any](mask *types.FieldMask[T]) *string { if mask == nil { return nil @@ -262,7 +308,7 @@ type endpointInfoWire struct { EnableServerlessCompute *bool `json:"enable_serverless_compute,omitempty"` WarehouseType WarehouseType `json:"warehouse_type,omitempty"` NumClusters *int `json:"num_clusters,omitempty"` - NumActiveSessions *int64 `json:"num_active_sessions,omitempty"` + NumActiveSessions *wireInt64 `json:"num_active_sessions,omitempty"` State EndpointState `json:"state,omitempty"` JdbcUrl *string `json:"jdbc_url,omitempty"` OdbcParams *odbcParamsWire `json:"odbc_params,omitempty"` @@ -281,6 +327,10 @@ func endpointInfoFromWire(w *endpointInfoWire) (*EndpointInfo, error) { if err != nil { return nil, fmt.Errorf("%s: %w", "EndpointInfo.Channel", err) } + numActiveSessionsPublicValue, err := int64FromWire(w.NumActiveSessions) + if err != nil { + return nil, fmt.Errorf("%s: %w", "EndpointInfo.NumActiveSessions", err) + } odbcParamsPublicValue, err := odbcParamsFromWire(w.OdbcParams) if err != nil { return nil, fmt.Errorf("%s: %w", "EndpointInfo.OdbcParams", err) @@ -305,7 +355,7 @@ func endpointInfoFromWire(w *endpointInfoWire) (*EndpointInfo, error) { EnableServerlessCompute: w.EnableServerlessCompute, WarehouseType: w.WarehouseType, NumClusters: w.NumClusters, - NumActiveSessions: w.NumActiveSessions, + NumActiveSessions: numActiveSessionsPublicValue, State: w.State, JdbcUrl: w.JdbcUrl, OdbcParams: odbcParamsPublicValue, @@ -384,7 +434,7 @@ type getWarehouseResponseWire struct { EnableServerlessCompute *bool `json:"enable_serverless_compute,omitempty"` WarehouseType WarehouseType `json:"warehouse_type,omitempty"` NumClusters *int `json:"num_clusters,omitempty"` - NumActiveSessions *int64 `json:"num_active_sessions,omitempty"` + NumActiveSessions *wireInt64 `json:"num_active_sessions,omitempty"` State EndpointState `json:"state,omitempty"` JdbcUrl *string `json:"jdbc_url,omitempty"` OdbcParams *odbcParamsWire `json:"odbc_params,omitempty"` @@ -403,6 +453,10 @@ func getWarehouseResponseFromWire(w *getWarehouseResponseWire) (*GetWarehouseRes if err != nil { return nil, fmt.Errorf("%s: %w", "GetWarehouseResponse.Channel", err) } + numActiveSessionsPublicValue, err := int64FromWire(w.NumActiveSessions) + if err != nil { + return nil, fmt.Errorf("%s: %w", "GetWarehouseResponse.NumActiveSessions", err) + } odbcParamsPublicValue, err := odbcParamsFromWire(w.OdbcParams) if err != nil { return nil, fmt.Errorf("%s: %w", "GetWarehouseResponse.OdbcParams", err) @@ -427,7 +481,7 @@ func getWarehouseResponseFromWire(w *getWarehouseResponseWire) (*GetWarehouseRes EnableServerlessCompute: w.EnableServerlessCompute, WarehouseType: w.WarehouseType, NumClusters: w.NumClusters, - NumActiveSessions: w.NumActiveSessions, + NumActiveSessions: numActiveSessionsPublicValue, State: w.State, JdbcUrl: w.JdbcUrl, OdbcParams: odbcParamsPublicValue, @@ -722,17 +776,21 @@ func warehouseTypePairFromWire(w *warehouseTypePairWire) (*WarehouseTypePair, er } type listWarehousesRequestWire struct { - RunAsUserId *int64 `json:"run_as_user_id,omitempty"` - PageSize *int `json:"page_size,omitempty"` - PageToken *string `json:"page_token,omitempty"` + RunAsUserId *wireInt64 `json:"run_as_user_id,omitempty"` + PageSize *int `json:"page_size,omitempty"` + PageToken *string `json:"page_token,omitempty"` } func listWarehousesRequestToWire(v *ListWarehousesRequest) (*listWarehousesRequestWire, error) { if v == nil { return nil, nil } + runAsUserIdWireValue, err := int64ToWire(v.RunAsUserId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "ListWarehousesRequest.RunAsUserId", err) + } return &listWarehousesRequestWire{ - RunAsUserId: v.RunAsUserId, + RunAsUserId: runAsUserIdWireValue, PageSize: v.PageSize, PageToken: v.PageToken, }, nil diff --git a/workspaces/CHANGELOG.md b/workspaces/CHANGELOG.md index 6224c04..19f237c 100644 --- a/workspaces/CHANGELOG.md +++ b/workspaces/CHANGELOG.md @@ -1,3 +1,5 @@ # Version changelog +## Release v0.0.1-dev.2 (2026-09-02) + ## Release v0.0.1-dev.1 (2026-08-20) diff --git a/workspaces/go.mod b/workspaces/go.mod index 3023c4d..774a977 100644 --- a/workspaces/go.mod +++ b/workspaces/go.mod @@ -9,12 +9,20 @@ replace github.com/databricks/sdk-go/core => ../core replace github.com/databricks/sdk-go/options => ../options require ( - github.com/databricks/sdk-go/auth v0.0.1-dev.1 - github.com/databricks/sdk-go/core v0.0.1-dev.1 - github.com/databricks/sdk-go/options v0.0.1-dev.1 + github.com/databricks/sdk-go/auth v0.0.1-dev.2 + github.com/databricks/sdk-go/core v0.0.1-dev.2 + github.com/databricks/sdk-go/options v0.0.1-dev.2 ) require ( + github.com/databricks/databricks-sdk-go v0.92.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/workspaces/internal/version.go b/workspaces/internal/version.go index 3384e0c..c2e5d81 100644 --- a/workspaces/internal/version.go +++ b/workspaces/internal/version.go @@ -2,4 +2,4 @@ package internal const ModuleName = "sdk-go-workspaces" -const Version = "0.0.1-dev.1" +const Version = "0.0.1-dev.2" diff --git a/workspaces/v1/client.go b/workspaces/v1/client.go old mode 100755 new mode 100644 index 4dd4fff..589b46b --- a/workspaces/v1/client.go +++ b/workspaces/v1/client.go @@ -112,8 +112,8 @@ func NewClient(ctx context.Context, opts ...client.Option) (*Client, error) { // // [Create a new workspace using the Account API]: http://docs.databricks.com/administration-guide/account-api/new-workspace.html // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) createWorkspacePublicBase(ctx context.Context, req *CreateWorkspaceRequest, opts ...call.Option) (*Workspace, error) { - wireReq, err := createWorkspaceRequestToWire(req) +func (c *internalClient) createWorkspacePublicBase(ctx context.Context, req CreateWorkspaceRequest, opts ...call.Option) (*Workspace, error) { + wireReq, err := createWorkspaceRequestToWire(&req) if err != nil { return nil, err } @@ -218,7 +218,7 @@ func (c *internalClient) createWorkspacePublicBase(ctx context.Context, req *Cre // account. // // [Create a new workspace using the Account API]: http://docs.databricks.com/administration-guide/account-api/new-workspace.html -func (c *internalClient) CreateWorkspacePublic(ctx context.Context, req *CreateWorkspaceRequest, opts ...call.Option) (*CreateWorkspacePublicWaiter, error) { +func (c *internalClient) CreateWorkspacePublic(ctx context.Context, req CreateWorkspaceRequest, opts ...call.Option) (*CreateWorkspacePublicWaiter, error) { accountID := c.accountID if req.AccountId != nil && *req.AccountId != "" { accountID = *req.AccountId @@ -239,14 +239,19 @@ func (c *internalClient) CreateWorkspacePublic(ctx context.Context, req *CreateW // CreateWorkspacePublicWaiter tracks the state of the operation started by CreateWorkspacePublic. type CreateWorkspacePublicWaiter struct { - poll func(context.Context, *GetWorkspaceRequest, ...call.Option) (*Workspace, error) + poll func(context.Context, GetWorkspaceRequest, ...call.Option) (*Workspace, error) accountID string workspaceId int64 } +// GetWorkspaceId returns the WorkspaceId value used to identify the operation. +func (w *CreateWorkspacePublicWaiter) GetWorkspaceId() int64 { + return w.workspaceId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *CreateWorkspacePublicWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetWorkspaceRequest{ + pollResp, err := w.poll(ctx, GetWorkspaceRequest{ AccountId: &w.accountID, WorkspaceId: &w.workspaceId, }, opts...) @@ -272,7 +277,7 @@ func (w *CreateWorkspacePublicWaiter) Done(ctx context.Context, opts ...call.Opt func (w *CreateWorkspacePublicWaiter) Wait(ctx context.Context, opts ...lro.Option) (*Workspace, error) { var result *Workspace poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetWorkspaceRequest{ + pollResp, err := w.poll(ctx, GetWorkspaceRequest{ AccountId: &w.accountID, WorkspaceId: &w.workspaceId, }) @@ -308,7 +313,7 @@ func (w *CreateWorkspacePublicWaiter) Wait(ctx context.Context, opts ...lro.Opti // Deletes a workspace, both specified by ID. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) DeleteWorkspacePublic(ctx context.Context, req *DeleteWorkspaceRequest, opts ...call.Option) (*Workspace, error) { +func (c *internalClient) DeleteWorkspacePublic(ctx context.Context, req DeleteWorkspaceRequest, opts ...call.Option) (*Workspace, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -325,7 +330,11 @@ func (c *internalClient) DeleteWorkspacePublic(ctx context.Context, req *DeleteW pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/workspaces/") - pb.singleSegment(*req.WorkspaceId) + if req.WorkspaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.WorkspaceId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -380,7 +389,7 @@ func (c *internalClient) DeleteWorkspacePublic(ctx context.Context, req *DeleteW // // [Create a new workspace using the Account API]: http://docs.databricks.com/administration-guide/account-api/new-workspace.html // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) GetWorkspacePublic(ctx context.Context, req *GetWorkspaceRequest, opts ...call.Option) (*Workspace, error) { +func (c *internalClient) GetWorkspacePublic(ctx context.Context, req GetWorkspaceRequest, opts ...call.Option) (*Workspace, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -397,7 +406,11 @@ func (c *internalClient) GetWorkspacePublic(ctx context.Context, req *GetWorkspa pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/workspaces/") - pb.singleSegment(*req.WorkspaceId) + if req.WorkspaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.WorkspaceId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} baseURL.RawQuery = queryParams.Encode() @@ -444,7 +457,7 @@ func (c *internalClient) GetWorkspacePublic(ctx context.Context, req *GetWorkspa // Lists workspaces for an account. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) ListWorkspacesPublic(ctx context.Context, req *ListWorkspacesRequest, opts ...call.Option) (*ListWorkspacesResponse, error) { +func (c *internalClient) ListWorkspacesPublic(ctx context.Context, req ListWorkspacesRequest, opts ...call.Option) (*ListWorkspacesResponse, error) { headers := http.Header{} headers.Set("Content-Type", "application/json") @@ -510,8 +523,8 @@ func (c *internalClient) ListWorkspacesPublic(ctx context.Context, req *ListWork // Updates a workspace. // Account-level method. Uses the Client's accountID, overridable per call via req.AccountId. -func (c *internalClient) updateWorkspacePublicBase(ctx context.Context, req *UpdateWorkspaceRequest, opts ...call.Option) (*Workspace, error) { - wireReq, err := updateWorkspaceRequestToWire(req) +func (c *internalClient) updateWorkspacePublicBase(ctx context.Context, req UpdateWorkspaceRequest, opts ...call.Option) (*Workspace, error) { + wireReq, err := updateWorkspaceRequestToWire(&req) if err != nil { return nil, err } @@ -532,7 +545,11 @@ func (c *internalClient) updateWorkspacePublicBase(ctx context.Context, req *Upd pb.literal("/api/2.0/accounts/") pb.singleSegment(accountID) pb.literal("/workspaces/") - pb.singleSegment(*req.CustomerFacingWorkspace.WorkspaceId) + if req.CustomerFacingWorkspace == nil || req.CustomerFacingWorkspace.WorkspaceId == nil { + pb.singleSegment("") + } else { + pb.singleSegment(*req.CustomerFacingWorkspace.WorkspaceId) + } baseURL.Path, baseURL.RawPath = pb.build() queryParams := url.Values{} if err := addQueryValue(queryParams, "update_mask", wireReq.UpdateMask); err != nil { @@ -582,7 +599,7 @@ func (c *internalClient) updateWorkspacePublicBase(ctx context.Context, req *Upd } // Updates a workspace. -func (c *internalClient) UpdateWorkspacePublic(ctx context.Context, req *UpdateWorkspaceRequest, opts ...call.Option) (*UpdateWorkspacePublicWaiter, error) { +func (c *internalClient) UpdateWorkspacePublic(ctx context.Context, req UpdateWorkspaceRequest, opts ...call.Option) (*UpdateWorkspacePublicWaiter, error) { accountID := c.accountID resp, err := c.updateWorkspacePublicBase(ctx, req, opts...) if err != nil { @@ -600,14 +617,19 @@ func (c *internalClient) UpdateWorkspacePublic(ctx context.Context, req *UpdateW // UpdateWorkspacePublicWaiter tracks the state of the operation started by UpdateWorkspacePublic. type UpdateWorkspacePublicWaiter struct { - poll func(context.Context, *GetWorkspaceRequest, ...call.Option) (*Workspace, error) + poll func(context.Context, GetWorkspaceRequest, ...call.Option) (*Workspace, error) accountID string workspaceId int64 } +// GetWorkspaceId returns the WorkspaceId value used to identify the operation. +func (w *UpdateWorkspacePublicWaiter) GetWorkspaceId() int64 { + return w.workspaceId +} + // Done polls once and reports whether the operation has reached a terminal state. func (w *UpdateWorkspacePublicWaiter) Done(ctx context.Context, opts ...call.Option) (bool, error) { - pollResp, err := w.poll(ctx, &GetWorkspaceRequest{ + pollResp, err := w.poll(ctx, GetWorkspaceRequest{ AccountId: &w.accountID, WorkspaceId: &w.workspaceId, }, opts...) @@ -633,7 +655,7 @@ func (w *UpdateWorkspacePublicWaiter) Done(ctx context.Context, opts ...call.Opt func (w *UpdateWorkspacePublicWaiter) Wait(ctx context.Context, opts ...lro.Option) (*Workspace, error) { var result *Workspace poll := func(ctx context.Context) error { - pollResp, err := w.poll(ctx, &GetWorkspaceRequest{ + pollResp, err := w.poll(ctx, GetWorkspaceRequest{ AccountId: &w.accountID, WorkspaceId: &w.workspaceId, }) diff --git a/workspaces/v1/genhelper.go b/workspaces/v1/genhelper.go old mode 100755 new mode 100644 index ef7b4a3..0cf05c1 --- a/workspaces/v1/genhelper.go +++ b/workspaces/v1/genhelper.go @@ -199,11 +199,12 @@ func flattenQueryValue(params url.Values, key string, value any) { } } -// pathBuilder assembles a request path from static literals and parameter -// values. It tracks the decoded path and its percent-escaped wire form in -// lockstep so build() can assign both url.URL.Path and url.URL.RawPath; because -// RawPath is a valid escaping of Path, url.URL.String() emits it verbatim -// instead of re-escaping (which would double-encode "%"). +// pathBuilder assembles request paths so "/" in parameter values remains a +// path separator while characters that cannot appear literally in a URL path +// are percent-encoded when the request URL is serialized. +// +// It builds url.URL.Path and url.URL.RawPath together. net/url uses RawPath only +// when it is a valid encoding of Path; otherwise it escapes Path. type pathBuilder struct { path strings.Builder raw strings.Builder @@ -216,13 +217,14 @@ func (b *pathBuilder) literal(s string) { b.raw.WriteString(s) } -// singleSegment appends a single-segment path parameter: the value occupies one -// path segment, so everything is escaped, including "/". The value is formatted -// with %v so strings, enums, and numbers all work. +// singleSegment appends the value unchanged to Path and RawPath. When the URL +// is serialized, net/url keeps "/" literal and percent-encodes characters such +// as spaces, "?", and "#". +// The value is formatted with %v so strings, enums, and numbers all work. func (b *pathBuilder) singleSegment(v any) { s := fmt.Sprintf("%v", v) b.path.WriteString(s) - b.raw.WriteString(url.PathEscape(s)) + b.raw.WriteString(s) } // multiSegments appends a multi-segment path parameter: the value spans several diff --git a/workspaces/v1/wire.go b/workspaces/v1/wire.go old mode 100755 new mode 100644 index d41a714..6498621 --- a/workspaces/v1/wire.go +++ b/workspaces/v1/wire.go @@ -3,11 +3,57 @@ package workspaces import ( + "bytes" + "encoding/json" "fmt" + "strconv" "github.com/databricks/sdk-go/core/types" ) +type wireInt64 int64 + +func (v *wireInt64) UnmarshalJSON(data []byte) error { + data = bytes.TrimSpace(data) + if string(data) == "null" { + return fmt.Errorf("parse int64: null is not valid") + } + if len(data) > 0 && data[0] == '"' { + var text string + if err := json.Unmarshal(data, &text); err != nil { + return err + } + parsed, err := strconv.ParseInt(text, 10, 64) + if err != nil { + return fmt.Errorf("parse int64 %q: %w", text, err) + } + *v = wireInt64(parsed) + return nil + } + var parsed int64 + if err := json.Unmarshal(data, &parsed); err != nil { + return err + } + *v = wireInt64(parsed) + return nil +} + +func int64ToWire(v *int64) (*wireInt64, error) { + if v == nil { + return nil, nil + } + converted := wireInt64(*v) + return &converted, nil +} + +func int64FromWire(v *wireInt64) (*int64, error) { + if v == nil { + return nil, nil + } + converted := int64(*v) + return &converted, nil +} + func fieldMaskToWire[T any](mask *types.FieldMask[T]) *string { if mask == nil { return nil @@ -274,10 +320,10 @@ func updateWorkspaceRequestToWire(v *UpdateWorkspaceRequest) (*updateWorkspaceRe } type workspaceWire struct { - WorkspaceId *int64 `json:"workspace_id,omitempty"` + WorkspaceId *wireInt64 `json:"workspace_id,omitempty"` WorkspaceName *string `json:"workspace_name,omitempty"` AwsRegion *string `json:"aws_region,omitempty"` - CreationTime *int64 `json:"creation_time,omitempty"` + CreationTime *wireInt64 `json:"creation_time,omitempty"` DeploymentName *string `json:"deployment_name,omitempty"` WorkspaceStatus WorkspaceStatus `json:"workspace_status,omitempty"` AccountId *string `json:"account_id,omitempty"` @@ -307,6 +353,14 @@ func workspaceToWire(v *Workspace) (*workspaceWire, error) { if v == nil { return nil, nil } + workspaceIdWireValue, err := int64ToWire(v.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Workspace.WorkspaceId", err) + } + creationTimeWireValue, err := int64ToWire(v.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Workspace.CreationTime", err) + } networkWireValue, err := workspaceNetworkToWire(v.Network) if err != nil { return nil, fmt.Errorf("%s: %w", "Workspace.Network", err) @@ -343,10 +397,10 @@ func workspaceToWire(v *Workspace) (*workspaceWire, error) { return nil, fmt.Errorf("%s: unsupported oneof implementation %T", "Workspace.NetworkConfig", value) } return &workspaceWire{ - WorkspaceId: v.WorkspaceId, + WorkspaceId: workspaceIdWireValue, WorkspaceName: v.WorkspaceName, AwsRegion: v.AwsRegion, - CreationTime: v.CreationTime, + CreationTime: creationTimeWireValue, DeploymentName: v.DeploymentName, WorkspaceStatus: v.WorkspaceStatus, AccountId: v.AccountId, @@ -387,6 +441,14 @@ func workspaceFromWire(w *workspaceWire) (*Workspace, error) { if networkConfigMembers > 1 { return nil, fmt.Errorf("%s: multiple oneof members set", "Workspace.NetworkConfig") } + workspaceIdPublicValue, err := int64FromWire(w.WorkspaceId) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Workspace.WorkspaceId", err) + } + creationTimePublicValue, err := int64FromWire(w.CreationTime) + if err != nil { + return nil, fmt.Errorf("%s: %w", "Workspace.CreationTime", err) + } networkPublicValue, err := workspaceNetworkFromWire(w.Network) if err != nil { return nil, fmt.Errorf("%s: %w", "Workspace.Network", err) @@ -415,10 +477,10 @@ func workspaceFromWire(w *workspaceWire) (*Workspace, error) { networkConfigSelection = &Workspace_NetworkConfig_GcpManagedNetworkConfig{GcpManagedNetworkConfig: *networkConfigGcpManagedNetworkConfigConverted} } return &Workspace{ - WorkspaceId: w.WorkspaceId, + WorkspaceId: workspaceIdPublicValue, WorkspaceName: w.WorkspaceName, AwsRegion: w.AwsRegion, - CreationTime: w.CreationTime, + CreationTime: creationTimePublicValue, DeploymentName: w.DeploymentName, WorkspaceStatus: w.WorkspaceStatus, AccountId: w.AccountId,