diff --git a/Supabase.sln b/Supabase.sln index b1f00ba7..1d6eb725 100644 --- a/Supabase.sln +++ b/Supabase.sln @@ -1,3 +1,4 @@ + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.2.32519.379 @@ -31,24 +32,110 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SupabaseExample", "Examples EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{F7E6F0F9-19B4-403B-A5C8-36D43CDC6B5F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "spike-nswag", "nswag-spike\spike-nswag.csproj", "{BCD2B6A6-CC2E-49CE-AEDF-0C5142C9AA4F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "codegen-spike", "codegen-spike", "{47588DCA-5ABD-A496-6AD5-79735C1CDEBD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "spike-kiota", "kiota-spike\spike-kiota.csproj", "{2272ADA9-E00B-4667-B668-6AC30DE39E3E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "spike-kiota.TestRun", "kiota-testrun\spike-kiota.TestRun.csproj", "{3EF11C23-DD09-470F-A389-DD4FE8150605}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "spike-nswag.TestRun", "nswag-testrun\spike-nswag.TestRun.csproj", "{2DE2F56D-8496-477B-8682-0309A5222D32}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {FAE80407-C121-47A3-9304-D39FA828E9F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FAE80407-C121-47A3-9304-D39FA828E9F1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FAE80407-C121-47A3-9304-D39FA828E9F1}.Debug|x64.ActiveCfg = Debug|Any CPU + {FAE80407-C121-47A3-9304-D39FA828E9F1}.Debug|x64.Build.0 = Debug|Any CPU + {FAE80407-C121-47A3-9304-D39FA828E9F1}.Debug|x86.ActiveCfg = Debug|Any CPU + {FAE80407-C121-47A3-9304-D39FA828E9F1}.Debug|x86.Build.0 = Debug|Any CPU {FAE80407-C121-47A3-9304-D39FA828E9F1}.Release|Any CPU.ActiveCfg = Release|Any CPU {FAE80407-C121-47A3-9304-D39FA828E9F1}.Release|Any CPU.Build.0 = Release|Any CPU + {FAE80407-C121-47A3-9304-D39FA828E9F1}.Release|x64.ActiveCfg = Release|Any CPU + {FAE80407-C121-47A3-9304-D39FA828E9F1}.Release|x64.Build.0 = Release|Any CPU + {FAE80407-C121-47A3-9304-D39FA828E9F1}.Release|x86.ActiveCfg = Release|Any CPU + {FAE80407-C121-47A3-9304-D39FA828E9F1}.Release|x86.Build.0 = Release|Any CPU {28EE4F80-74AA-46F6-B15E-27C30310401A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {28EE4F80-74AA-46F6-B15E-27C30310401A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28EE4F80-74AA-46F6-B15E-27C30310401A}.Debug|x64.ActiveCfg = Debug|Any CPU + {28EE4F80-74AA-46F6-B15E-27C30310401A}.Debug|x64.Build.0 = Debug|Any CPU + {28EE4F80-74AA-46F6-B15E-27C30310401A}.Debug|x86.ActiveCfg = Debug|Any CPU + {28EE4F80-74AA-46F6-B15E-27C30310401A}.Debug|x86.Build.0 = Debug|Any CPU {28EE4F80-74AA-46F6-B15E-27C30310401A}.Release|Any CPU.ActiveCfg = Release|Any CPU {28EE4F80-74AA-46F6-B15E-27C30310401A}.Release|Any CPU.Build.0 = Release|Any CPU + {28EE4F80-74AA-46F6-B15E-27C30310401A}.Release|x64.ActiveCfg = Release|Any CPU + {28EE4F80-74AA-46F6-B15E-27C30310401A}.Release|x64.Build.0 = Release|Any CPU + {28EE4F80-74AA-46F6-B15E-27C30310401A}.Release|x86.ActiveCfg = Release|Any CPU + {28EE4F80-74AA-46F6-B15E-27C30310401A}.Release|x86.Build.0 = Release|Any CPU {F73BCB1B-1EEE-41FA-B7A7-C655F391A26D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F73BCB1B-1EEE-41FA-B7A7-C655F391A26D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F73BCB1B-1EEE-41FA-B7A7-C655F391A26D}.Debug|x64.ActiveCfg = Debug|Any CPU + {F73BCB1B-1EEE-41FA-B7A7-C655F391A26D}.Debug|x64.Build.0 = Debug|Any CPU + {F73BCB1B-1EEE-41FA-B7A7-C655F391A26D}.Debug|x86.ActiveCfg = Debug|Any CPU + {F73BCB1B-1EEE-41FA-B7A7-C655F391A26D}.Debug|x86.Build.0 = Debug|Any CPU {F73BCB1B-1EEE-41FA-B7A7-C655F391A26D}.Release|Any CPU.ActiveCfg = Release|Any CPU {F73BCB1B-1EEE-41FA-B7A7-C655F391A26D}.Release|Any CPU.Build.0 = Release|Any CPU + {F73BCB1B-1EEE-41FA-B7A7-C655F391A26D}.Release|x64.ActiveCfg = Release|Any CPU + {F73BCB1B-1EEE-41FA-B7A7-C655F391A26D}.Release|x64.Build.0 = Release|Any CPU + {F73BCB1B-1EEE-41FA-B7A7-C655F391A26D}.Release|x86.ActiveCfg = Release|Any CPU + {F73BCB1B-1EEE-41FA-B7A7-C655F391A26D}.Release|x86.Build.0 = Release|Any CPU + {BCD2B6A6-CC2E-49CE-AEDF-0C5142C9AA4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BCD2B6A6-CC2E-49CE-AEDF-0C5142C9AA4F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BCD2B6A6-CC2E-49CE-AEDF-0C5142C9AA4F}.Debug|x64.ActiveCfg = Debug|Any CPU + {BCD2B6A6-CC2E-49CE-AEDF-0C5142C9AA4F}.Debug|x64.Build.0 = Debug|Any CPU + {BCD2B6A6-CC2E-49CE-AEDF-0C5142C9AA4F}.Debug|x86.ActiveCfg = Debug|Any CPU + {BCD2B6A6-CC2E-49CE-AEDF-0C5142C9AA4F}.Debug|x86.Build.0 = Debug|Any CPU + {BCD2B6A6-CC2E-49CE-AEDF-0C5142C9AA4F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BCD2B6A6-CC2E-49CE-AEDF-0C5142C9AA4F}.Release|Any CPU.Build.0 = Release|Any CPU + {BCD2B6A6-CC2E-49CE-AEDF-0C5142C9AA4F}.Release|x64.ActiveCfg = Release|Any CPU + {BCD2B6A6-CC2E-49CE-AEDF-0C5142C9AA4F}.Release|x64.Build.0 = Release|Any CPU + {BCD2B6A6-CC2E-49CE-AEDF-0C5142C9AA4F}.Release|x86.ActiveCfg = Release|Any CPU + {BCD2B6A6-CC2E-49CE-AEDF-0C5142C9AA4F}.Release|x86.Build.0 = Release|Any CPU + {2272ADA9-E00B-4667-B668-6AC30DE39E3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2272ADA9-E00B-4667-B668-6AC30DE39E3E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2272ADA9-E00B-4667-B668-6AC30DE39E3E}.Debug|x64.ActiveCfg = Debug|Any CPU + {2272ADA9-E00B-4667-B668-6AC30DE39E3E}.Debug|x64.Build.0 = Debug|Any CPU + {2272ADA9-E00B-4667-B668-6AC30DE39E3E}.Debug|x86.ActiveCfg = Debug|Any CPU + {2272ADA9-E00B-4667-B668-6AC30DE39E3E}.Debug|x86.Build.0 = Debug|Any CPU + {2272ADA9-E00B-4667-B668-6AC30DE39E3E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2272ADA9-E00B-4667-B668-6AC30DE39E3E}.Release|Any CPU.Build.0 = Release|Any CPU + {2272ADA9-E00B-4667-B668-6AC30DE39E3E}.Release|x64.ActiveCfg = Release|Any CPU + {2272ADA9-E00B-4667-B668-6AC30DE39E3E}.Release|x64.Build.0 = Release|Any CPU + {2272ADA9-E00B-4667-B668-6AC30DE39E3E}.Release|x86.ActiveCfg = Release|Any CPU + {2272ADA9-E00B-4667-B668-6AC30DE39E3E}.Release|x86.Build.0 = Release|Any CPU + {3EF11C23-DD09-470F-A389-DD4FE8150605}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3EF11C23-DD09-470F-A389-DD4FE8150605}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3EF11C23-DD09-470F-A389-DD4FE8150605}.Debug|x64.ActiveCfg = Debug|Any CPU + {3EF11C23-DD09-470F-A389-DD4FE8150605}.Debug|x64.Build.0 = Debug|Any CPU + {3EF11C23-DD09-470F-A389-DD4FE8150605}.Debug|x86.ActiveCfg = Debug|Any CPU + {3EF11C23-DD09-470F-A389-DD4FE8150605}.Debug|x86.Build.0 = Debug|Any CPU + {3EF11C23-DD09-470F-A389-DD4FE8150605}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3EF11C23-DD09-470F-A389-DD4FE8150605}.Release|Any CPU.Build.0 = Release|Any CPU + {3EF11C23-DD09-470F-A389-DD4FE8150605}.Release|x64.ActiveCfg = Release|Any CPU + {3EF11C23-DD09-470F-A389-DD4FE8150605}.Release|x64.Build.0 = Release|Any CPU + {3EF11C23-DD09-470F-A389-DD4FE8150605}.Release|x86.ActiveCfg = Release|Any CPU + {3EF11C23-DD09-470F-A389-DD4FE8150605}.Release|x86.Build.0 = Release|Any CPU + {2DE2F56D-8496-477B-8682-0309A5222D32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2DE2F56D-8496-477B-8682-0309A5222D32}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2DE2F56D-8496-477B-8682-0309A5222D32}.Debug|x64.ActiveCfg = Debug|Any CPU + {2DE2F56D-8496-477B-8682-0309A5222D32}.Debug|x64.Build.0 = Debug|Any CPU + {2DE2F56D-8496-477B-8682-0309A5222D32}.Debug|x86.ActiveCfg = Debug|Any CPU + {2DE2F56D-8496-477B-8682-0309A5222D32}.Debug|x86.Build.0 = Debug|Any CPU + {2DE2F56D-8496-477B-8682-0309A5222D32}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2DE2F56D-8496-477B-8682-0309A5222D32}.Release|Any CPU.Build.0 = Release|Any CPU + {2DE2F56D-8496-477B-8682-0309A5222D32}.Release|x64.ActiveCfg = Release|Any CPU + {2DE2F56D-8496-477B-8682-0309A5222D32}.Release|x64.Build.0 = Release|Any CPU + {2DE2F56D-8496-477B-8682-0309A5222D32}.Release|x86.ActiveCfg = Release|Any CPU + {2DE2F56D-8496-477B-8682-0309A5222D32}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -57,6 +144,10 @@ Global {43FFFE0C-91D2-43AB-913F-B3824702AE49} = {F94175FC-DE2B-4DBC-9C79-2A97B8489412} {5B805377-7615-441C-86B1-4BE203B0289B} = {43FFFE0C-91D2-43AB-913F-B3824702AE49} {F73BCB1B-1EEE-41FA-B7A7-C655F391A26D} = {F7E6F0F9-19B4-403B-A5C8-36D43CDC6B5F} + {BCD2B6A6-CC2E-49CE-AEDF-0C5142C9AA4F} = {47588DCA-5ABD-A496-6AD5-79735C1CDEBD} + {2272ADA9-E00B-4667-B668-6AC30DE39E3E} = {47588DCA-5ABD-A496-6AD5-79735C1CDEBD} + {3EF11C23-DD09-470F-A389-DD4FE8150605} = {47588DCA-5ABD-A496-6AD5-79735C1CDEBD} + {2DE2F56D-8496-477B-8682-0309A5222D32} = {47588DCA-5ABD-A496-6AD5-79735C1CDEBD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {832DE89D-7252-4B03-9301-BB8D36B40992} diff --git a/codegen-comparison.md b/codegen-comparison.md new file mode 100644 index 00000000..447a5234 --- /dev/null +++ b/codegen-comparison.md @@ -0,0 +1,434 @@ +# Codegen toolchain comparison — supabase-csharp (SDK-1107) + +This document evaluates which toolchain, if any, should generate the HTTP layer of the C# SDK from +the shared contract models. It is the root summary; each toolchain has a detailed write-up in its +spike folder. Findings, measurements, and version numbers are as of July 2026. + +- **NSwag** → [`nswag-spike/evaluation-nswag.md`](nswag-spike/evaluation-nswag.md) · project `spike-nswag` +- **Kiota** → [`kiota-spike/evaluation-kiota.md`](kiota-spike/evaluation-kiota.md) · project `spike-kiota` +- Background: [`nswag-spike/findings/`](nswag-spike/findings) (Smithy PR review + raw-spec spikes) + +## Executive summary + +The SDK ships working, hand-written transport, and its model types are published public API on +NuGet. Evaluated against that baseline, neither generated client improves on the current code; +generated models add value, but not by replacing existing types in the short term. The two +toolchains that were run differ as follows: + +- **Kiota.** The generated client is AOT-safe, streams as generated, and delegates transport to a + runtime. Adopting it would replace maintained, working transport with 4,338 generated LOC plus an + 8-package runtime (see *Cost analysis*). Its models implement `IParsable`, which places + `Microsoft.Kiota.Abstractions` on the SDK's public API; keeping the public API free of Kiota + types would require a hand-written DTO and mapping layer in addition to the wrapper, which + removes the benefit of generating the models. + +- **NSwag.** The generated client duplicates the per-operation transport the SDK already implements + in `MakeRequest` and adds no capability. Its models are plain POCOs with no dependency beyond + System.Text.Json and can be used without the client or any NSwag runtime. + +The decisive property is separability: NSwag's models can be adopted without its client; Kiota's +output cannot be split from its runtime. + +Because the SDK is a published package, exposing generated models in place of the existing public +types is a breaking change, and mapping between generated and exposed types would erase most of the +benefit of generating them (see *Consumer impact*). The near-term value of generated models is +therefore not replacement but: (1) detecting and prioritising drift between the SDK and the shared +contract, and (2) providing the model types for new endpoints as they are implemented. + +**Recommendation, in two stages:** *Stage 1 (now)* — generate models with NSwag in models-only +mode; use them as the type source for newly implemented endpoints and as a drift monitor against +the existing public types; change no existing public API. *Stage 2 (next major version)* — decide +whether generated types replace the existing ones, bundled with the breaking changes already +planned for the feature-parity catch-up, and conditional on the contract source having proven +reliable. Details, conditions, and reversal criteria follow. + +This recommendation is specific to an SDK with owned working transport, a published public API, +and a feature-parity backlog. For an SDK built from scratch, the same evaluation produces a +different answer; *Scope of validity* states which constraints drive the conclusion and what +changes without them. + +## Scope and method + +- **Input:** the committed Smithy→OpenAPI artifacts from `supabase/sdk#51`. The C# SDK consumes the + OpenAPI output; Smithy is never run in the C# toolchain. The same `*.ready.json` files were fed + to every generator. +- **Target architecture:** any generated client is internal, placed beneath a hand-written + ergonomic wrapper (query builder, session loop, streaming/progress, auth). The evaluation + questions follow from this: can the models be owned and exposed directly, is the transport an + improvement, and does the generator's runtime reach the public API. +- **Idiomatic bar:** `HttpClient`, System.Text.Json, `#nullable enable`, streaming in both + directions (`Stream`), .NET 6+/AOT/trimming, NuGet-clean packaging, minimal dependencies. +- **Determinism:** all toolchains evaluated are template-based generators whose output is a + function of the input document and configuration only; regeneration is reproducible and involves + no generative-AI component. + +## Toolchains evaluated + +| Toolchain | Status | Assessment | +|---|---|---| +| **NSwag → CSharpClient** | ✅ run | Plain, dependency-free output; models are usable POCOs. Remaining local fixes: null-omission serialization config, AOT (source-generated serializer context), naming. Optional-field typing and streaming schemas fixed upstream (supabase/sdk#55). Recommended, in models-only mode. | +| **Kiota (Microsoft)** | ✅ run | Client is AOT-safe, streams as generated, delegates transport to a runtime. Requires an 8-package runtime; models expose Kiota types on the public API. Not recommended unless a whole generated client and runtime are adopted fleet-wide. | +| **@typespec/http-client-csharp** | ⏸ assessed, not run | Consumes TypeSpec, not OpenAPI, so it would require an OpenAPI→TypeSpec conversion step; emits `System.ClientModel`-dependent code. Relevant only if the organisation adopts TypeSpec as source of truth. | +| **OpenAPI Generator → csharp** | ⏸ assessed, not run | Default output is RestSharp-based; an `httpclient` option exists. Assessed as adding no capability beyond NSwag's models. | +| **Speakeasy** | ⏸ assessed, not run | Commercial; requires an account and API key; introduces vendor lock-in into an OSS pipeline. | +| **Smithy → C#** | ❌ excluded | No official C# emitter exists; this route would require building one. | + +NSwag and Kiota were run and are compared in detail below; the remaining toolchains were assessed +and not pursued for the reasons stated above and in *Coverage of the remaining options*. + +## Evaluation against the current SDK + +The baseline is the hand-written client in production. For Storage, the service used as generator +input, the current implementation is 2,511 LOC: `StorageFileApi.cs` (907), `StorageBucketApi.cs` +(155), ~600 LOC of streaming-progress and upload-caching ergonomics, interfaces and option types, +and ~200–260 LOC of wire DTOs (`Bucket`, `FileObject`, `FileObjectV2`, `UploadSignedUrl`, +`SearchOptions`, request options). For GoTrue: `Client.cs` <1k, `Api.cs` ~800. This code is +maintained end-to-end by the team, with `FailureHint` error mapping and no third-party runtime +dependency. Each generated artifact, judged against that baseline: + +| Generated artifact | Improvement over current code? | Reason | +|---|---|---| +| **Kiota client** | No | Provides AOT-safe serialization and streaming as generated, but replaces maintained, working transport with 4,338 generated LOC plus an 8-package runtime, provides none of the current ergonomics (upload progress, caching, `FailureHint` mapping), and still requires the wrapper to be hand-written on top. | +| **NSwag client** | No | Re-implements the `MakeRequest` transport the SDK already has, without refactoring and without the current error mapping, serializer injection, and dynamic headers. | +| **Kiota models** | No | Runtime-coupled (`IParsable`): exposing them places `Kiota.Abstractions` on the public API, a dependency the current hand-written models do not impose. | +| **NSwag models** | Yes, conditional | Plain POCOs, equivalent in shape to the current hand-written DTOs, but generated from the shared contract, which protects against cross-SDK drift. As the SDK's model types are published API, the integration path matters as much as the artifact: new endpoints and drift monitoring first, replacement only at a major version (see *Consumer impact*). | +| **Transport techniques** | One | `HttpCompletionOption.ResponseHeadersRead` is applicable to `Core` independently of any adoption decision. | + +Adoption is per artifact, not per tool: a client can be rejected while its models, or a single +technique, are adopted. + +## NSwag vs Kiota — observed properties (same Storage input, both compile) + +| Dimension | NSwag | Kiota | +|---|---|---| +| Output shape | 1 file, flat client + models (2,889 LOC) | request-builder tree, 51 files (4,338 LOC) | +| Call style | `client.ListBucketsAsync()` | `client.Bucket["id"].DeleteAsync()` | +| Model naming | `File_size_limit` (snake_case retained) | `FileSizeLimit` (PascalCase) | +| Model coupling | plain POCOs (`[JsonPropertyName]` only), usable standalone | `IParsable` + `IAdditionalDataHolder`, coupled to the Kiota runtime | +| Runtime dependencies | none (System.Text.Json only) | 8 packages (`Microsoft.Kiota.*` + `Std.UriTemplate`) | +| AOT / trimming | ❌ reflection-based System.Text.Json + enum reflection | ✅ explicit `IParsable`, no reflection | +| Streaming response | ✅ `FileResponse.Stream` as generated — required a `byte→binary` schema fix, since applied upstream (supabase/sdk#55) | ✅ `Task` as generated | +| Streaming upload | ✅ `Stream` → `StreamContent` as generated — required an inline-binary schema fix, since applied upstream (supabase/sdk#55) | ✅ `Stream` / `MultipartBody` as generated | +| Transport placement | inlined in the generated code (~86 LOC per operation), no runtime dependency; regenerated on each run | in an external 8-package runtime; generated code only builds requests | +| Domain error mapping | wrap `ApiException`, retaining `FailureHint` | generic typed errors; domain reasons rebuilt by hand | +| Middleware seam | `DelegatingHandler` + `PrepareRequest`/`ProcessResponse` partials | handler pipeline (retry, redirect, auth); the builder tree does not offer a partial-class seam | +| Suitability for wrapping | flat client + POCO returns; direct to wrap and re-expose | builder tree designed for direct use; extension happens through the handler pipeline | +| Dependency maintenance (as of July 2026) | community project led by Rico Suter with contributors; actively maintained, tracks .NET 10 (v14.7.1). In models-only mode no NSwag runtime ships, so tool abandonment does not affect built output | Microsoft-owned; actively maintained (kiota-dotnet 2.0.0, May 2026); used by the Microsoft Graph SDKs. The runtime ships as a permanent dependency of the SDK | +| Adoption as a whole client | inline transport in generated code, wrapped by hand | factored runtime + builder tree, wrapped by hand | +| Adoption as models only | ✅ POCOs usable without the client | ❌ not possible; models require the runtime | +| Public-API exposure | none (System.Text.Json is a base dependency) | models place `Kiota.Abstractions` on the public surface | + +## Live-run results (`kiota-testrun`, `nswag-testrun`) + +Both generated clients were run against a local platform (`supabase start`). The runs exercised +Storage operations; the Functions and Database clients were generated and compiled but not +exercised against the platform. Both runs confirmed that HttpClient injection and streaming upload +work. They also surfaced defects that static analysis had not, with different failure modes per +tool: + +- **Shared model defect (both tools):** the list endpoints return bare JSON arrays, but the model + wraps them in an envelope (`{items:[]}`). Kiota deserializes the mismatch into an object whose + `Items` is null and returns an empty result with no error; NSwag throws an `ApiException` on + deserialization. The same upstream defect therefore produces a silent wrong result in one tool + and an explicit failure in the other. +- **NSwag-specific defect:** NSwag serializes every optional field at its default value + (`file_size_limit:0`, `limit:0`, `sortBy:null`), and the server rejects several of these: a + bucket created with `file_size_limit:0` rejects all uploads with 413; `limit:0` and + `sortBy:null` return 400. Kiota omits unset fields, so the equivalent calls succeeded. NSwag's + request DTOs were therefore not usable as generated from the original artifacts; the fix has two + halves — nullable value types (model-side, since fixed upstream) and `WhenWritingNull` + (client-side configuration). Details are in each `evaluation-*.md`. + +**Cause of the divergence, given the same spec.** The OpenAPI marks these fields optional but not +`nullable`, leaving optionality under-specified; the two generators fill the gap with opposite +defaults. Kiota maps optional value types to `double?` and omits nulls on serialization, producing +minimal, valid bodies. NSwag maps them to non-nullable `double` (default `0`) and serializes every +field, producing bodies the server rejects. This is a difference in generator defaults against an +under-specified schema, not an intrinsic property of either tool, and the NSwag side is fixable +(mark the fields `nullable` upstream, or configure `DefaultIgnoreCondition = WhenWritingNull` with +nullable value types). + +Model quality therefore has two independent axes, and the tools divide across them: + +| Axis | Favours | Reason | +|---|---|---| +| Usability under a wrapper (ownership, exposability) | NSwag | plain POCOs; Kiota's `IParsable` models expose the runtime on the public API | +| Request-serialization correctness as generated | Kiota | Kiota omits unset members; NSwag writes them as explicit nulls, which the server rejects for some fields (`limit`). Typing no longer differs — both map optional scalars to nullable types since supabase/sdk#55 | + +These two results differ in kind: Kiota's coupling is structural (there is no plain-model output), +while NSwag's serialization gap is a configuration and annotation fix — the annotation half has +since landed upstream (supabase/sdk#55); the configuration half (`WhenWritingNull`) remains a +client-side setting. NSwag can be made correct while remaining dependency-free; Kiota's models +cannot be decoupled from its runtime. + +A further conclusion applies regardless of tool: generated models are only as correct as the source +model. The defects found by the live runs are located in the shared contract model — a work in +progress at the time of this spike — not in the generators, which both translated their input +faithfully and reproducibly. That determinism works in the pipeline's favour: a defect exists once, +in the model, and its fix propagates identically to every SDK on regeneration, where the equivalent +defect in hand-written SDKs would be introduced and fixed per SDK. The corollary is that validation +must target the model: the API evolves, so model accuracy is a state to maintain rather than reach +once, and a live contract test of this kind should be a permanent stage in any adopted pipeline — +it validates the model, not the generators. + +### Upstream resolution and rerun (July 2026) + +The model defects above were fixed in supabase/sdk#55 (list-envelope unwrap, optional-scalar +nullability, streaming `byte→binary` for Functions/TUS/Database payloads, greedy-label cleanup, +build reproducibility), and the spike was rerun against the corrected artifacts — same generator +versions, and for the first time with no local pre-patching of the spec: + +- **Both clients compile with 0 errors** from the committed artifacts as-is (the raw spec + previously produced 24 C# compile errors without a local wildcard patch). +- **Kiota live harness: 4/4 pass.** `ListBuckets` returns real counts (previously a silent 0); + `ListObjects` counts the uploaded object. +- **NSwag live harness:** `ListBuckets` deserializes (previously threw); `CreateBucket` succeeds + without `file_size_limit` — the server accepts `null` as unset, so the 413-bucket failure is + gone; streaming upload works. `ListObjects` still returns 400: NSwag serializes unset members as + explicit nulls and the server rejects `limit: null` (it tolerates `file_size_limit: null` — + null-tolerance is per-field). This is the generator-side half of the serialization fix + (`WhenWritingNull`), unchanged in the recommendation. +- **NSwag Functions/TUS signatures now stream as generated** (`Stream` body; `FileResponse` via + `ResponseHeadersRead`) — the `byte→binary` patch is no longer a local step. The live Functions + run remains open (requires a deployed edge function). + +The rerun is one complete turn of the loop the contract pipeline requires: generate → validate +against a live platform → fix the model once → regenerate, with every SDK inheriting the fix. + +## Cost analysis — generated vs. hand-maintained code + +For Storage, the like-for-like sizes are: 2,511 hand-written LOC today, 2,889 generated by NSwag, +4,338 generated by Kiota. The LOC parity with NSwag overstates the generated client's coverage: the +hand-written 2,511 includes upload-progress reporting, upload caching, and `FailureHint` error +mapping, none of which either generated client provides. Generated code is not authored by the team +but is not cost-free; the comparison is between unowned generated code plus a pipeline, and owned +code the team can edit directly. + +| | Generate (whole client) | Hand-maintain (current) | +|---|---|---| +| LOC | 4,338 (Kiota) / 2,889 (NSwag), not authored by the team | 2,511 (Storage), authored by the team, including ergonomics the generated clients lack | +| Fixing a defect | regenerate, or work around it; defects in Kiota's runtime require an upstream fix | edit in place and ship | +| Standing cost | contract-model upstream + OpenAPI patches + naming/AOT configuration + regeneration on drift + (Kiota) the runtime's dependency lifecycle | ongoing reading, debugging, and manual handling of drift | +| Defects observed in the live run | envelope and serialization-default defects, located in generated code and fixed through the model or configuration rather than the code itself | not exercised | +| Readability / debugging | requires understanding the generator's output and, for Kiota, its runtime | already understood by the team | + +The slice where generation is justified is small and measurable: the wire DTOs amount to ~200–260 +LOC in today's Storage implementation. Generating them is not a labour saving at that size; the +benefit is that they derive from the shared contract, which is what protects against cross-SDK +drift. For the client, generation replaces a similar-sized, owned, working implementation (with +more functionality) by a larger, unowned one; whether that trade is acceptable is a build-versus-buy +decision that tips toward generation only if the organisation operates the contract pipeline +fleet-wide, so that the C# SDK reuses existing infrastructure. For C# in isolation, hand-maintaining +the owned surface is the cheaper option. + +## Consumer impact — integrating generated models into a published SDK + +The SDK's model types (`Bucket`, `FileObject`, …) are published public API. There are three ways to +integrate generated models, with different costs: + +- **(a) Replace the existing types.** A breaking change requiring a revalidation pass. Its cost + depends on the vehicle: as a standalone break it is the most expensive option; bundled into an + already-planned major version it is marginal, since revalidation is paid per major release, not + per change. The SDK's feature-parity backlog implies such a major version is coming. The scope of + revalidation can also be bounded: with naming and namespaces aligned, replacement is largely a + type-identity change with unchanged behaviour, and the semantic risk concentrates in the + nullability fix (`int` → `int?` on optional fields), which changes signatures and behaviour. +- **(b) Map between generated and exposed types.** A hand-written mapping layer. This is the same + cost identified for Kiota's models, and it removes most of the benefit of generating models. +- **(c) Integrate at the edges and monitor.** Use generated models where new endpoints introduce + new types, and diff generated models against the existing public types to detect drift. No + existing API changes. + +Option (c) carries a hybrid risk — generated and hand-written types coexisting in one package. Two +rules bound it: extend an existing type when a new endpoint touches one, rather than introducing a +parallel generated type; and treat coexistence as a transition that converges at the next major +version, not as a permanent state. + +**Drift monitoring is a report, not a build gate.** The SDK is currently behind the contract on +feature parity, so divergence between generated and existing types is expected and cannot fail a +build without blocking unrelated work. The workable design is a committed baseline of the current +diff, with only new deltas surfaced, triaged into two classes: + +1. **Divergence on implemented surface** — the SDK exposes the endpoint/type but its shape + disagrees with the contract: an SDK defect or an upstream contract change; high priority. +2. **Contract surface with no SDK counterpart** — endpoints or fields the SDK has not implemented: + input to the feature-parity backlog and its prioritisation. + +This makes the generated models useful immediately — as a drift detector and a backlog signal — +while deferring all public-API decisions to a major version. + +## Key findings + +1. **Models are the only layer where generation adds value.** The generated operation layers either + duplicate the existing `MakeRequest` transport without refactoring (NSwag) or move transport + into an external runtime (Kiota); the ergonomic layer (query builder, streaming/progress/TUS, + session loop, Auth) is hand-written in every scenario. The candidate artifact is the set of + model DTOs. + +2. **The wrapper architecture determines the tool.** With a generated client kept internal beneath + a hand-written wrapper, the wrapper's return types are where a generator's runtime can reach the + public API: + - NSwag models are plain POCOs and can be used directly, with no third-party dependency. + - Kiota models implement `IParsable`; returning one places `Microsoft.Kiota.Abstractions` on the + public API as a transitive dependency for every consumer. Avoiding this requires a hand-written + DTO and mapping layer, which removes the benefit of generating models; and because Kiota's + models require its runtime, there is no models-only adoption path. + +3. **In a published SDK, the integration path outweighs the artifact.** Generated models deliver + near-term value as a drift monitor and as the type source for new endpoints; replacing existing + public types is a major-version decision whose cost depends on what it is bundled with. + +Kiota's capabilities (AOT safety, streaming as generated, PascalCase naming) apply only when the +entire Kiota stack is adopted, which is the opposite of the internal-client, owned-wrapper design. + +## TypeSpec (`@typespec/http-client-csharp`) — assessed, not pursued + +The TypeSpec option covers two distinct routes: + +1. **`TypeSpec → @typespec/openapi3 → `** — `@typespec/openapi3` emits an OpenAPI + document only; it does not select the C# generator. Given an OpenAPI document, the generator + choice is the same one evaluated above. The SDK already receives OpenAPI from the contract + pipeline, so this route produces no input that is not already available. +2. **`@typespec/http-client-csharp`** — the distinct toolchain (Microsoft's TypeSpec C# emitter, + Azure-SDK lineage). Two findings, the second decisive: + - **Input mismatch.** It consumes TypeSpec, not OpenAPI. The contract pipeline under evaluation + emits OpenAPI, so this route would require a lossy OpenAPI→TypeSpec conversion step running + counter to that pipeline. + - **Runtime-coupled models, as with Kiota.** It emits whole clients on `System.ClientModel`, and + its models implement `System.ClientModel`'s serialization interfaces (`IJsonModel`). The + models therefore expose `System.ClientModel` on the public API in the same way Kiota's models + expose `Kiota.Abstractions`, and cannot be exposed without a separate DTO and mapping layer. + +**Assessment:** not pursued. It reproduces the Kiota outcome (runtime-coupled models, no +models-only path) and adds an input-format conversion. It would become relevant only if the +organisation adopted TypeSpec as the fleet source of truth — and in that case the C# conclusion is +unchanged: emit OpenAPI via `@typespec/openapi3` and generate models with NSwag; the TypeSpec +client emitter would still not fit the wrapper architecture. + +## Coverage of the remaining options + +OpenAPI→C# generators fall into two families, and both have been sampled: + +- **Whole-client generators** — Kiota, `@typespec/http-client-csharp`, OpenAPI Generator's default: + runtime-coupled models, public-API exposure, no models-only path. +- **DTO/POCO generators** — NSwag (OpenAPI Generator's models are also plain POCOs): models usable + independently of the client. + +The remaining named options do not add a third family: OpenAPI Generator (csharp) produces plain +models comparable to NSwag's with a RestSharp- or `generichost`-based client, adding no capability +over NSwag in models-only mode; Speakeasy is commercial with vendor lock-in; Refit/Refitter is a +different paradigm (Refit-attributed interfaces plus a Refit runtime dependency) that does not +address the models-only requirement; Smithy-native C# has no emitter. Further trials would not +change the conclusion, because the conclusion is architectural rather than tool-specific: client +generation replaces owned working transport, and only plain POCO models fit the wrapper +architecture. The one alternative of a different kind is in-house templating or Roslyn source +generation — a build-versus-buy decision rather than another tool to trial. + +## Recommendation — adapt, with NSwag in models-only mode, in two stages + +### Stage 1 — now; no change to existing public API + +- **Set up NSwag models-only generation** from the committed OpenAPI, with the three fixes required + before any generated type ships (the first two surfaced by the live runs): + - *Serialization correctness* — configure `DefaultIgnoreCondition = WhenWritingNull` so unset + members are omitted rather than sent as explicit nulls (the server rejects `limit: null`). + The typing half — nullable optional value types — is fixed upstream (supabase/sdk#55) and + verified by the rerun; without `WhenWritingNull`, `ListObjects` still returns 400 (see + *Live-run results*). + - *AOT/trimming* — add a source-generated `[JsonSerializable] JsonSerializerContext` for the + generated models and replace the reflection-based enum `ConvertToString`. + - *Naming* — map generated names to PascalCase (generator configuration or a post-processing + step); `File_size_limit` does not meet the public-API bar. +- **Use generated models for new endpoints** implemented during the feature-parity catch-up, + extending existing types where an endpoint touches one rather than introducing parallel types. +- **Stand up the drift monitor** described in *Consumer impact*: committed baseline, new deltas + reported and triaged into defects (implemented surface) and backlog input (unimplemented + surface). +- **Adopt `HttpCompletionOption.ResponseHeadersRead`** in `Core`, independently of the above. +- **Do not adopt Kiota:** its client replaces owned, working transport with an unowned builder tree + plus runtime, without improving on the current code, and its models cannot serve the public API + without a redundant DTO and mapping layer. +- **Model gaps reported and fixed upstream** — the shared model, not the tool choice, was the + larger risk, and supabase/sdk#55 implements the fixes for everything the live runs surfaced: + the list-response envelope, optional-scalar nullability, streaming `byte→binary` + (Functions/TUS/Database), the `{wildcardPath+}` label, and build reproducibility. Verified by + rerunning both generators and the live harnesses against the fixed artifacts (see *Live-run + results*). Still open upstream: **Auth** (unmodelled — needs models or a formal scope-out) and + write operations modelling `200` only (the API can return `204`). + +### Stage 2 — at the next major version + +- **Decide whether generated types replace the existing public model types**, bundled with the + breaking changes already planned for the feature-parity catch-up, so that the break and the + revalidation pass are paid once. +- Preconditions: the contract source has proven reliable through Stage-1 monitoring, and the + remaining upstream gaps (Auth modelling, `204` responses) are resolved. If they are not, Stage 1 + continues as-is — the drift monitor remains a prioritisation tool and no public API changes. + +## Scope of validity + +The recommendation follows from three facts about this SDK's current position, not from properties +of code generation itself: + +- transport exists, works, and is owned — a generated client replaces working code rather than + adding capability; +- the model types are published public API — exposing generated types is either a breaking change + or a mapping layer; +- the SDK is behind the contract on feature parity — divergence from the specification is backlog, + not regression. + +For an SDK built from scratch, none of these constraints exists: there is no transport to replace, +no published API to break, and no accumulated drift. Under those conditions the same evaluation +produces a different answer — whole-client generation becomes the natural starting point, and +Kiota is the strongest candidate assessed here (AOT-safe, streaming as generated, Microsoft- +maintained runtime), with its runtime dependency accepted as a day-one design decision rather than +introduced as a migration cost. + +Two findings carry over to a greenfield setting unchanged, with greater weight: + +1. **Generated code is only as correct as the contract it is generated from.** A greenfield SDK + has no hand-written baseline to diff against, so silent model defects of the kind found in the + live runs (list-envelope, nullability) would ship directly to production. +2. **A live contract-test harness is therefore a required pipeline stage from the first release**, + not a hardening step added later. + +The conclusions in this document should not be applied to other SDKs or to new SDKs without +re-running the evaluation against their own baselines. + +## Conditions, risks, and deliverables + +**Deliverables.** + +1. The NSwag models-only pipeline with the three fixes (serialization, AOT, naming). +2. The drift monitor: generated models diffed against public types, committed baseline, two-class + triage. +3. Upstream fixes to the shared model — delivered in supabase/sdk#55 (list envelopes, nullability, + streaming, path labels, build reproducibility); Auth modelling remains open. The higher-leverage + work, benefiting every SDK. +4. A live contract-test harness (`*-testrun`) as a permanent pipeline stage — the mechanism that + catches model-versus-production drift before it ships across the fleet. +5. The Stage-2 replacement decision, prepared as part of the next major release. + +**Status of the contract source.** The organisation is evaluating Smithy as the modelling IDL; the +model is under active development and there is no committed rollout. The defects found by the live +runs were consistent with that work-in-progress status; they have since been fixed in +supabase/sdk#55 and verified by rerunning the spike against the corrected artifacts — one complete +turn of the generate → validate-live → fix-the-model loop the pipeline requires. The C# requirement +is narrower than the IDL decision: a reliable, validated OpenAPI document maintained as the +contract artifact, from whichever IDL emits it — Smithy and TypeSpec both output OpenAPI, and the +C# toolchain consumes only the OpenAPI document. The spike's findings (model gaps and their fixes) +are input to that evaluation. Stage 1 does not depend on the outcome: the drift monitor functions +against an imperfect specification and contributes to validating it. Stage 2 does depend on it. + +**Reversal criteria.** Stop generation entirely if the OpenAPI contract artifact ceases to be +maintained. Do not proceed to Stage 2 if the shared model remains unvalidated or if only +runtime-coupled toolchains remain acceptable; in that case the existing hand-written types stay. + +**Change triggers.** If the organisation mandates TypeSpec as source of truth, the conclusion is +unchanged (TypeSpec emits OpenAPI; the generator choice above still applies). If the team decides +to stop owning transport and adopt a whole generated client and runtime fleet-wide, reassess Kiota, +which is the stronger candidate for that scenario. + +**Summary:** generate the wire data types with NSwag; use them first to monitor and prioritise +drift and to build new endpoints; align the existing public types at the next major version if the +contract source proves reliable; do not ship a generated client. diff --git a/kiota-spike/.gitignore b/kiota-spike/.gitignore new file mode 100644 index 00000000..c315cf74 --- /dev/null +++ b/kiota-spike/.gitignore @@ -0,0 +1,3 @@ +# Spike build output — not part of the artifact +bin/ +obj/ diff --git a/kiota-spike/README.md b/kiota-spike/README.md new file mode 100644 index 00000000..1d7c5e60 --- /dev/null +++ b/kiota-spike/README.md @@ -0,0 +1,47 @@ +# Kiota codegen spike (C# SDK · SDK-1107) + +Comparison point for the NSwag spike (`../nswag-spike`). Same input — the committed +Smithy→OpenAPI artifacts from `supabase/sdk#51` — run through **Microsoft Kiota** instead of NSwag. + +> ⚠️ **Spike, not shippable code.** Everything under `generated/` is machine-emitted and +> **not owned/maintainable**. Standalone project (`spike-kiota.csproj`, separate assembly) added to +> `Supabase.sln` for visibility only; **not referenced by `Supabase.csproj`**, analyzers disabled — +> does **not** affect the product's build/analyzers/quality metrics. Do not reference from the SDK. + +## Generated with + +```bash +dotnet tool install --global Microsoft.OpenApi.Kiota # Kiota 1.32.4 +kiota generate -l CSharp -d generated/StorageService.ready.json \ + -c StorageApiClient -n Supabase.Storage.Kiota -o generated/Storage --clean-output +# (Functions / Database identical) +``` + +## What it produced + +| Service | Files | Shape | +|---------|------:|-------| +| Storage | 51 | request-builder tree (`client.Bucket["id"].DeleteAsync()`) + models | +| Functions | 5 | " | +| Database | 5 | " | + +Runtime dependency: **`Microsoft.Kiota.Bundle`** → pulls 8 packages (`Kiota.Abstractions`, +`Http.HttpClientLibrary`, `Serialization.Json/Form/Text/Multipart`, `Std.UriTemplate`). + +## Why it exists / conclusion + +Per-toolchain detail: **[`evaluation-kiota.md`](evaluation-kiota.md)**. Cross-toolchain +comparison + overall recommendation: root **[`codegen-comparison.md`](../codegen-comparison.md)**. +In short: + +- **Kiota's strengths** — **AOT/trimming** (explicit `IParsable`, zero reflection) and **model + naming** (`FileSizeLimit`). Streaming was a differentiator against the original artifacts; since + `supabase/sdk#55` both tools stream as generated. +- **Kiota's blocker** for this SDK — **ownership**: 8 runtime packages, a request-builder tree, and + models coupled to the Kiota runtime (`IParsable`), so they **can't be lifted out standalone**. + That rules out the "models-only, plain POCOs" path NSwag supports. + +**Recommendation: NSwag in models-only mode for supabase-csharp** (plain, zero-dep, usable without +the client). Kiota is the candidate only if adopting a *whole* generated client + its runtime +fleet-wide, or for an SDK built from scratch (see the root document's *Scope of validity*). NSwag's +AOT gap is closable in-place via a source-gen `JsonSerializerContext`. diff --git a/kiota-spike/evaluation-kiota.md b/kiota-spike/evaluation-kiota.md new file mode 100644 index 00000000..7ec783b5 --- /dev/null +++ b/kiota-spike/evaluation-kiota.md @@ -0,0 +1,130 @@ +# Kiota evaluation — answers to the spike brief (SDK-1107) + +Tool: Kiota 1.32.4 (`kiota generate -l CSharp`), input = committed Smithy→OpenAPI from +`supabase/sdk#51` (same `*.ready.json` inputs as the NSwag spike). All three services generated +and compiled on netstandard2.1 (see `spike-kiota.csproj`). + +Legend: ✅ works as-generated · 🟡 works with a model/patch or caveat · ❌ not achievable. + +## What's produced + +A **request-builder tree**, not a flat client: one builder class per path segment. + +| Service | Files | Example call | +|---|---:|---| +| Storage | 51 | `client.Bucket.GetAsync()`, `client.Bucket["id"].DeleteAsync()`, `client.ObjectNamespace[...]...PostAsync(multipart)` | +| Functions | 5 | `client.Functions.V1["name"].PostAsync(stream)` | +| Database | 5 | `client.Table["name"].GetAsync(cfg)` | + +- Models are separate files, **proper PascalCase** (`FileSizeLimit`, `AllowedMimeTypes`). +- Each operation is thin (~12 LOC): build `RequestInformation` → `RequestAdapter.SendAsync(...)`. + **All real transport lives in the Kiota runtime**, not in generated code. +- Runtime dependency: **`Microsoft.Kiota.Bundle`** → 8 packages (`Kiota.Abstractions`, + `Http.HttpClientLibrary`, `Serialization.Json/Form/Text/Multipart`, `Std.UriTemplate`). + +## Question-by-question + +### 1. Streaming uploads — ✅ (better than NSwag) +- **Functions/raw-binary body:** generated as `PostAsync(System.IO.Stream body, …)` — native stream, + **no model patch needed** (Kiota maps `application/octet-stream` → `Stream` even with the + `format:byte` payload that made NSwag JSON-serialize). +- **Multipart (`UploadObject`/`UpdateObject`):** `PostAsync(MultipartBody body, …)` — Kiota's native + `MultipartBody` (from `Serialization.Multipart`); the file part is a `Stream`. + +### 2. Streaming responses — ✅ (better than NSwag) +Binary/octet responses generate as `Task` via `RequestAdapter.SendPrimitiveAsync`, +read through the runtime with response-headers-read semantics. **No byte→binary model patch +needed** (NSwag required one). Exposes `Stream`, not `IAsyncEnumerable` — brief accepts +either. + +### 3. HttpClient injection — ✅ +Client is constructed with an `IRequestAdapter`; `HttpClientRequestAdapter` accepts an externally +supplied `HttpClient` (DI / `IHttpClientFactory`). + +### 4. Middleware / handlers — ✅ (with a caveat) +Kiota ships a middleware **handler pipeline** (retry, redirect, auth, telemetry) on the request +adapter — richer than NSwag's partial hooks. Caveat: the **request-builder tree resists the +`partial`-class seam** — you extend behavior via handlers/the adapter, not by owning half a partial. + +### 5. Multipart uploads — ✅ +Native `MultipartBody` with a streaming `Stream` file part (see Q1). The injected multipart schema's +required non-file parts carry through (same model wart as NSwag). + +### 6. Auth flows — ❌ (not modelled) +Auth is absent from `supabase/sdk#51`; nothing to generate. Same conclusion as NSwag: HTTP ops +would be generatable once modelled, session/refresh/PKCE stay hand-written. Model gap to raise. + +### 7. PostgREST query builder — 🟡 minimal +Same as NSwag: generates the row/RPC builders + models; the fluent `.eq()/.select()/.order()` +builder stays entirely hand-written (row bodies are dynamic). Kiota adds no query-builder help. + +### 8. AOT / trimming — ✅ (no reflection) +Serialization is **explicit `IParsable`** (`GetFieldDeserializers()` / `Serialize(ISerializationWriter)`) +— **zero reflection**, 0 `JsonSerializer` calls in generated code. Trim/NativeAOT-safe by +construction; the Kiota runtime libs are trimmable. This is exactly where NSwag fails. + +### 9. Unity compatibility — 🟡 +netstandard2.1 + reflection-free serialization is IL2CPP-friendlier than NSwag. Not verified under +Unity here, but structurally the better of the two. The 8-package runtime is extra surface to ship. + +### 10. Model gaps found +Same upstream gaps as the NSwag pass (Auth unmodelled; `{wildcardPath+}`; required multipart parts; +write-ops 200-only). Notably Kiota did **not** need the Functions `byte→binary` fix — it streams +octet-stream regardless — so that gap is NSwag-specific, not a shared-model defect. + +**NEW — surfaced by the live test-run (`../kiota-testrun`), not by static analysis:** the model's +**list response shapes are wrong vs production**. The real Storage API returns **bare JSON arrays**: +``` +GET /bucket → [ {...} ] +POST /object/list/{bucket} → [ {...} ] +``` +but the Smithy model wraps them (`structure ListBucketsOutput { @required items: BucketList }`), so +the generated `ListBucketsResponseContent` / `ListObjectsResponseContent` expose an `.Items` envelope +that **never matches**. The client deserializes the top-level array into an object → `.Items` is +`null` → returns **0 silently** (no error). This is a call that succeeds while returning wrong +data — the failure mode hardest to detect — and it is **tool-independent** (NSwag emits the same +envelope from the same model) and hits **every SDK**. It is a model-not-validated-against-production +defect: the modelled shape does not match what the server sends. **Raise on `supabase/sdk`:** model the +list outputs as top-level lists (or fix the server contract). This is the most important gap found. + +**Update (July 2026):** fixed upstream in `supabase/sdk#55`. restJson1 cannot bind a list to the HTTP +payload, so `patch-openapi.py` unwraps the envelope in the generated OpenAPI; the model documents the +limitation. Verified by rerunning generation and the live harness against the corrected artifacts: +**4/4 pass** — `ListBuckets` returns real counts (the false-zero failure is gone) and `ListObjects` +counts the uploaded object. The same PR fixes the shared gaps listed above except **Auth** +(unmodelled) and the `200`-only write ops, which remain open. + +## Good / bad + +**Good** +- **AOT/trimming-safe** (explicit `IParsable`, no reflection) — the standout. +- **Streaming works as-generated** (Stream in/out, MultipartBody) with no model patching. +- **Proper PascalCase** model names out of the box. +- **Properly factored transport** + mature middleware (retry/redirect/auth) in the runtime. + +**Bad (for this SDK's wrapper architecture)** +- **8-package runtime dependency**, and it goes **public** (see below). +- **Models reach the public API.** Every model is + `public partial class X : IAdditionalDataHolder, IParsable` exposing + `Microsoft.Kiota.Abstractions.Serialization` types (`IParseNode`, `ISerializationWriter`). + Returning one from a wrapper puts `Microsoft.Kiota.Abstractions` on your public surface → forced + transitive dep on every consumer. **To stay Kiota-agnostic you must hand-write a full parallel + DTO layer + mapping** — which erases the reason to generate models at all. +- **External ownership**: request-builder tree (51 files) + external runtime; transport lives in + the runtime, not in code the team can edit. +- **No models-only path**: the models require the runtime, so they cannot be adopted without it. +- **No domain error mapping**: generic typed errors; `FailureHint`-style reasons are rebuilt by hand. +- **Resists the partial seam** used to own product-specific behavior. + +## Recommendation for supabase-csharp — **reject as an included artifact** +Kiota's client is AOT-safe, streams as generated, and delegates transport to a maintained runtime. +It fits **only if** the team adopts a *whole* generated client + the Kiota runtime fleet-wide and +hand-writes ergonomic wrappers over the builders — or for an SDK built from scratch, where there is +no owned transport to replace and no published API to break (see the root document's *Scope of +validity*). Under this SDK's model — generated code kept **internal beneath a hand-written +wrapper**, minimal dependencies — Kiota fails the decisive test: **its models cannot serve as the +SDK's DTOs without placing `Microsoft.Kiota.Abstractions` on the public API**, forcing a full +agnostic-DTO + mapping layer. That negates the one thing worth generating (usable models). + +See the root [`codegen-comparison.md`](../codegen-comparison.md) for the full comparison, the +two-stage adoption strategy, and its conditions; this document is the tool-level evidence. diff --git a/kiota-spike/generated/Database/DatabaseApiClient.cs b/kiota-spike/generated/Database/DatabaseApiClient.cs new file mode 100644 index 00000000..40a0ca33 --- /dev/null +++ b/kiota-spike/generated/Database/DatabaseApiClient.cs @@ -0,0 +1,56 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions; +using Microsoft.Kiota.Serialization.Form; +using Microsoft.Kiota.Serialization.Json; +using Microsoft.Kiota.Serialization.Multipart; +using Microsoft.Kiota.Serialization.Text; +using Supabase.Database.Kiota.Item; +using Supabase.Database.Kiota.Rpc; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System; +namespace Supabase.Database.Kiota +{ + /// + /// The main entry point of the SDK, exposes the configuration and the fluent API. + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class DatabaseApiClient : BaseRequestBuilder + { + /// The rpc property + public global::Supabase.Database.Kiota.Rpc.RpcRequestBuilder Rpc + { + get => new global::Supabase.Database.Kiota.Rpc.RpcRequestBuilder(PathParameters, RequestAdapter); + } + /// Gets an item from the Supabase.Database.Kiota.item collection + /// Unique identifier of the item + /// A + public global::Supabase.Database.Kiota.Item.WithTableItemRequestBuilder this[string position] + { + get + { + var urlTplParams = new Dictionary(PathParameters); + urlTplParams.Add("table", position); + return new global::Supabase.Database.Kiota.Item.WithTableItemRequestBuilder(urlTplParams, RequestAdapter); + } + } + /// + /// Instantiates a new and sets the default values. + /// + /// The request adapter to use to execute the requests. + public DatabaseApiClient(IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}", new Dictionary()) + { + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultDeserializer(); + ApiClientBuilder.RegisterDefaultDeserializer(); + ApiClientBuilder.RegisterDefaultDeserializer(); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Database/Item/WithTableItemRequestBuilder.cs b/kiota-spike/generated/Database/Item/WithTableItemRequestBuilder.cs new file mode 100644 index 00000000..1d52d2e4 --- /dev/null +++ b/kiota-spike/generated/Database/Item/WithTableItemRequestBuilder.cs @@ -0,0 +1,434 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using Supabase.Database.Kiota.Models; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Supabase.Database.Kiota.Item +{ + /// + /// Builds and executes requests for operations under \{table} + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithTableItemRequestBuilder : BaseRequestBuilder + { + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public WithTableItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/{table}{?columns*,filters*,limit*,offset*,on_conflict*,order*,select*}", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public WithTableItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/{table}{?columns*,filters*,limit*,offset*,on_conflict*,order*,select*}", rawUrl) + { + } + /// A + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task DeleteAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task DeleteAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + var requestInfo = ToDeleteRequestInformation(requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Database.Kiota.Models.DatabaseErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task GetAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + var requestInfo = ToGetRequestInformation(requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Database.Kiota.Models.DatabaseErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Binary request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PatchAsync(Stream body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PatchAsync(Stream body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPatchRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Database.Kiota.Models.DatabaseErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// Binary request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PostAsync(Stream body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PostAsync(Stream body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPostRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Database.Kiota.Models.DatabaseErrorResponseContent.CreateFromDiscriminatorValue }, + }; + await RequestAdapter.SendNoContentAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Binary request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PutAsync(Stream body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PutAsync(Stream body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPutRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Database.Kiota.Models.DatabaseErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToDeleteRequestInformation(Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToDeleteRequestInformation(Action> requestConfiguration = default) + { +#endif + var requestInfo = new RequestInformation(Method.DELETE, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/octet-stream, application/json"); + return requestInfo; + } + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToGetRequestInformation(Action> requestConfiguration = default) + { +#endif + var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/octet-stream, application/json"); + return requestInfo; + } + /// A + /// Binary request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPatchRequestInformation(Stream body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPatchRequestInformation(Stream body, Action> requestConfiguration = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.PATCH, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/octet-stream, application/json"); + requestInfo.SetStreamContent(body, "application/octet-stream"); + return requestInfo; + } + /// A + /// Binary request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPostRequestInformation(Stream body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPostRequestInformation(Stream body, Action> requestConfiguration = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.POST, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/octet-stream, application/json"); + requestInfo.SetStreamContent(body, "application/octet-stream"); + return requestInfo; + } + /// A + /// Binary request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPutRequestInformation(Stream body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPutRequestInformation(Stream body, Action> requestConfiguration = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.PUT, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/octet-stream, application/json"); + requestInfo.SetStreamContent(body, "application/octet-stream"); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Supabase.Database.Kiota.Item.WithTableItemRequestBuilder WithUrl(string rawUrl) + { + return new global::Supabase.Database.Kiota.Item.WithTableItemRequestBuilder(rawUrl, RequestAdapter); + } + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class WithTableItemRequestBuilderDeleteQueryParameters + #pragma warning restore CS1591 + { + /// Horizontal filters — rows matching these filters will be deleted. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("filters")] + public string? Filters { get; set; } +#nullable restore +#else + [QueryParameter("filters")] + public string Filters { get; set; } +#endif +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("select")] + public string? Select { get; set; } +#nullable restore +#else + [QueryParameter("select")] + public string Select { get; set; } +#endif + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithTableItemRequestBuilderDeleteRequestConfiguration : RequestConfiguration + { + } + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class WithTableItemRequestBuilderGetQueryParameters + #pragma warning restore CS1591 + { + /// Horizontal filters — each entry becomes a query parameter.Key: column name (or "or"/"and" for logical groups).Value: "{operator}.{value}" e.g. {"id": "eq.5", "name": "like.foo*"}.See FilterOperator for the full list of operators. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("filters")] + public string? Filters { get; set; } +#nullable restore +#else + [QueryParameter("filters")] + public string Filters { get; set; } +#endif + /// Maximum number of rows to return. + [QueryParameter("limit")] + public double? Limit { get; set; } + /// Row offset for pagination. + [QueryParameter("offset")] + public double? Offset { get; set; } + /// Ordering — e.g. "name.asc,age.desc.nullslast" +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("order")] + public string? Order { get; set; } +#nullable restore +#else + [QueryParameter("order")] + public string Order { get; set; } +#endif + /// Column selection — comma-separated, supports aliasing, casting, embeddedresources, and JSON operators. e.g. "id,name,orders(total,status)". +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("select")] + public string? Select { get; set; } +#nullable restore +#else + [QueryParameter("select")] + public string Select { get; set; } +#endif + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithTableItemRequestBuilderGetRequestConfiguration : RequestConfiguration + { + } + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class WithTableItemRequestBuilderPatchQueryParameters + #pragma warning restore CS1591 + { + /// Horizontal filters — rows matching these filters will be updated.Key: column name. Value: "{operator}.{value}" e.g. {"id": "eq.5"}. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("filters")] + public string? Filters { get; set; } +#nullable restore +#else + [QueryParameter("filters")] + public string Filters { get; set; } +#endif +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("select")] + public string? Select { get; set; } +#nullable restore +#else + [QueryParameter("select")] + public string Select { get; set; } +#endif + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithTableItemRequestBuilderPatchRequestConfiguration : RequestConfiguration + { + } + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class WithTableItemRequestBuilderPostQueryParameters + #pragma warning restore CS1591 + { + /// Restrict which columns may be populated (useful with CSV uploads). +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("columns")] + public string? Columns { get; set; } +#nullable restore +#else + [QueryParameter("columns")] + public string Columns { get; set; } +#endif + /// Columns to select in the returned representation (requires return=representation). +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("select")] + public string? Select { get; set; } +#nullable restore +#else + [QueryParameter("select")] + public string Select { get; set; } +#endif + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithTableItemRequestBuilderPostRequestConfiguration : RequestConfiguration + { + } + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class WithTableItemRequestBuilderPutQueryParameters + #pragma warning restore CS1591 + { + /// Horizontal filters — rows matching these filters will be upserted. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("filters")] + public string? Filters { get; set; } +#nullable restore +#else + [QueryParameter("filters")] + public string Filters { get; set; } +#endif + /// Columns to match for conflict detection (if not the primary key). +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("on_conflict")] + public string? OnConflict { get; set; } +#nullable restore +#else + [QueryParameter("on_conflict")] + public string OnConflict { get; set; } +#endif +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("select")] + public string? Select { get; set; } +#nullable restore +#else + [QueryParameter("select")] + public string Select { get; set; } +#endif + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithTableItemRequestBuilderPutRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Database/Models/DatabaseErrorResponseContent.cs b/kiota-spike/generated/Database/Models/DatabaseErrorResponseContent.cs new file mode 100644 index 00000000..1935b75f --- /dev/null +++ b/kiota-spike/generated/Database/Models/DatabaseErrorResponseContent.cs @@ -0,0 +1,98 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Database.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class DatabaseErrorResponseContent : ApiException, IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// PostgreSQL error code (e.g. "23505") or PostgREST error code (e.g. "PGRST301"). +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Code { get; set; } +#nullable restore +#else + public string Code { get; set; } +#endif + /// Extra context — constraint name, offending column, etc. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Details { get; set; } +#nullable restore +#else + public string Details { get; set; } +#endif + /// Hint from PostgreSQL. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Hint { get; set; } +#nullable restore +#else + public string Hint { get; set; } +#endif + /// The primary error message. + public override string Message { get => MessageEscaped ?? string.Empty; } + /// Human-readable error message. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? MessageEscaped { get; set; } +#nullable restore +#else + public string MessageEscaped { get; set; } +#endif + /// + /// Instantiates a new and sets the default values. + /// + public DatabaseErrorResponseContent() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Database.Kiota.Models.DatabaseErrorResponseContent CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Database.Kiota.Models.DatabaseErrorResponseContent(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "code", n => { Code = n.GetStringValue(); } }, + { "details", n => { Details = n.GetStringValue(); } }, + { "hint", n => { Hint = n.GetStringValue(); } }, + { "message", n => { MessageEscaped = n.GetStringValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("code", Code); + writer.WriteStringValue("details", Details); + writer.WriteStringValue("hint", Hint); + writer.WriteStringValue("message", MessageEscaped); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Database/Rpc/Item/WithFunctionNameItemRequestBuilder.cs b/kiota-spike/generated/Database/Rpc/Item/WithFunctionNameItemRequestBuilder.cs new file mode 100644 index 00000000..dbcb469d --- /dev/null +++ b/kiota-spike/generated/Database/Rpc/Item/WithFunctionNameItemRequestBuilder.cs @@ -0,0 +1,180 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using Supabase.Database.Kiota.Models; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Supabase.Database.Kiota.Rpc.Item +{ + /// + /// Builds and executes requests for operations under \rpc\{functionName} + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithFunctionNameItemRequestBuilder : BaseRequestBuilder + { + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public WithFunctionNameItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/rpc/{functionName}{?args*,select*}", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public WithFunctionNameItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/rpc/{functionName}{?args*,select*}", rawUrl) + { + } + /// A + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task GetAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + var requestInfo = ToGetRequestInformation(requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Database.Kiota.Models.DatabaseErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Binary request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PostAsync(Stream body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PostAsync(Stream body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPostRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Database.Kiota.Models.DatabaseErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToGetRequestInformation(Action> requestConfiguration = default) + { +#endif + var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/octet-stream, application/json"); + return requestInfo; + } + /// A + /// Binary request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPostRequestInformation(Stream body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPostRequestInformation(Stream body, Action> requestConfiguration = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.POST, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/octet-stream, application/json"); + requestInfo.SetStreamContent(body, "application/octet-stream"); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Supabase.Database.Kiota.Rpc.Item.WithFunctionNameItemRequestBuilder WithUrl(string rawUrl) + { + return new global::Supabase.Database.Kiota.Rpc.Item.WithFunctionNameItemRequestBuilder(rawUrl, RequestAdapter); + } + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class WithFunctionNameItemRequestBuilderGetQueryParameters + #pragma warning restore CS1591 + { + /// Function arguments — each entry becomes a query parameter.Keys and value formats are defined by the PostgreSQL function signature. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("args")] + public string? Args { get; set; } +#nullable restore +#else + [QueryParameter("args")] + public string Args { get; set; } +#endif +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("select")] + public string? Select { get; set; } +#nullable restore +#else + [QueryParameter("select")] + public string Select { get; set; } +#endif + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithFunctionNameItemRequestBuilderGetRequestConfiguration : RequestConfiguration + { + } + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class WithFunctionNameItemRequestBuilderPostQueryParameters + #pragma warning restore CS1591 + { +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("select")] + public string? Select { get; set; } +#nullable restore +#else + [QueryParameter("select")] + public string Select { get; set; } +#endif + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithFunctionNameItemRequestBuilderPostRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Database/Rpc/RpcRequestBuilder.cs b/kiota-spike/generated/Database/Rpc/RpcRequestBuilder.cs new file mode 100644 index 00000000..280f419e --- /dev/null +++ b/kiota-spike/generated/Database/Rpc/RpcRequestBuilder.cs @@ -0,0 +1,48 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions; +using Supabase.Database.Kiota.Rpc.Item; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System; +namespace Supabase.Database.Kiota.Rpc +{ + /// + /// Builds and executes requests for operations under \rpc + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class RpcRequestBuilder : BaseRequestBuilder + { + /// Gets an item from the Supabase.Database.Kiota.rpc.item collection + /// Unique identifier of the item + /// A + public global::Supabase.Database.Kiota.Rpc.Item.WithFunctionNameItemRequestBuilder this[string position] + { + get + { + var urlTplParams = new Dictionary(PathParameters); + urlTplParams.Add("functionName", position); + return new global::Supabase.Database.Kiota.Rpc.Item.WithFunctionNameItemRequestBuilder(urlTplParams, RequestAdapter); + } + } + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public RpcRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/rpc", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public RpcRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/rpc", rawUrl) + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Database/kiota-lock.json b/kiota-spike/generated/Database/kiota-lock.json new file mode 100644 index 00000000..e3bbd817 --- /dev/null +++ b/kiota-spike/generated/Database/kiota-lock.json @@ -0,0 +1,34 @@ +{ + "descriptionHash": "83E5BA347B88939BF3E9567114D9F4279CFAF151BEC56174673D92D14CC869A71988E468B8B8FA1EDCD325D975698B97F5B41697087310EB3CEED138CA7E9FAF", + "descriptionLocation": "../DatabaseService.ready.json", + "lockFileVersion": "1.0.0", + "kiotaVersion": "1.32.4", + "clientClassName": "DatabaseApiClient", + "typeAccessModifier": "Public", + "clientNamespaceName": "Supabase.Database.Kiota", + "language": "CSharp", + "usesBackingStore": false, + "excludeBackwardCompatible": false, + "includeAdditionalData": true, + "disableSSLValidation": false, + "serializers": [ + "Microsoft.Kiota.Serialization.Json.JsonSerializationWriterFactory", + "Microsoft.Kiota.Serialization.Text.TextSerializationWriterFactory", + "Microsoft.Kiota.Serialization.Form.FormSerializationWriterFactory", + "Microsoft.Kiota.Serialization.Multipart.MultipartSerializationWriterFactory" + ], + "deserializers": [ + "Microsoft.Kiota.Serialization.Json.JsonParseNodeFactory", + "Microsoft.Kiota.Serialization.Text.TextParseNodeFactory", + "Microsoft.Kiota.Serialization.Form.FormParseNodeFactory" + ], + "structuredMimeTypes": [ + "application/json", + "text/plain;q=0.9", + "application/x-www-form-urlencoded;q=0.2", + "multipart/form-data;q=0.1" + ], + "includePatterns": [], + "excludePatterns": [], + "disabledValidationRules": [] +} \ No newline at end of file diff --git a/kiota-spike/generated/DatabaseService.ready.json b/kiota-spike/generated/DatabaseService.ready.json new file mode 100644 index 00000000..470204f7 --- /dev/null +++ b/kiota-spike/generated/DatabaseService.ready.json @@ -0,0 +1,704 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Supabase Database API", + "version": "1.0", + "description": "PostgREST-backed database API.\n\nBase URL: https://{project-ref}.supabase.co/rest/v1\n\nKnown limitations:\n 1. Write operations return 204 (no body) by default and 200 with a body when\n Prefer: return=representation \u2014 the model uses 200 throughout so generators\n always produce body-parsing code; clients must tolerate empty bodies.\n 2. RPC GET arguments are function-specific; they are expressed via the same\n @httpQueryParams map as row filters, with function-defined keys." + }, + "paths": { + "/rpc/{functionName}": { + "get": { + "operationId": "CallRpcGet", + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "args", + "in": "query", + "description": "Function arguments \u2014 each entry becomes a query parameter.\nKeys and value formats are defined by the PostgreSQL function signature.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Accept-Profile", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "CallRpcGet 200 response", + "headers": { + "Content-Range": { + "schema": { + "type": "string" + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "post": { + "operationId": "CallRpcPost", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "Content-Profile", + "in": "header", + "schema": { + "type": "string" + } + }, + { + "name": "Prefer", + "in": "header", + "description": "e.g. \"params=single-object\" \u2014 treat the entire body as a single parameter.", + "schema": { + "type": "string", + "description": "e.g. \"params=single-object\" \u2014 treat the entire body as a single parameter." + } + } + ], + "responses": { + "200": { + "description": "CallRpcPost 200 response", + "headers": { + "Content-Range": { + "schema": { + "type": "string" + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + } + }, + "/{table}": { + "delete": { + "operationId": "DeleteRows", + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "filters", + "in": "query", + "description": "Horizontal filters \u2014 rows matching these filters will be deleted.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Content-Profile", + "in": "header", + "schema": { + "type": "string" + } + }, + { + "name": "Prefer", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "DeleteRows 200 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "get": { + "operationId": "SelectRows", + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "description": "Column selection \u2014 comma-separated, supports aliasing, casting, embedded\nresources, and JSON operators. e.g. \"id,name,orders(total,status)\".", + "schema": { + "type": "string", + "description": "Column selection \u2014 comma-separated, supports aliasing, casting, embedded\nresources, and JSON operators. e.g. \"id,name,orders(total,status)\"." + } + }, + { + "name": "order", + "in": "query", + "description": "Ordering \u2014 e.g. \"name.asc,age.desc.nullslast\"", + "schema": { + "type": "string", + "description": "Ordering \u2014 e.g. \"name.asc,age.desc.nullslast\"" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of rows to return.", + "schema": { + "type": "number", + "description": "Maximum number of rows to return." + } + }, + { + "name": "offset", + "in": "query", + "description": "Row offset for pagination.", + "schema": { + "type": "number", + "description": "Row offset for pagination." + } + }, + { + "name": "filters", + "in": "query", + "description": "Horizontal filters \u2014 each entry becomes a query parameter.\nKey: column name (or \"or\"/\"and\" for logical groups).\nValue: \"{operator}.{value}\" e.g. {\"id\": \"eq.5\", \"name\": \"like.foo*\"}.\nSee FilterOperator for the full list of operators.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Accept", + "in": "header", + "description": "Response format. e.g. \"application/json\" (default), \"text/csv\",\n\"application/vnd.pgrst.object+json\" (singular-row mode).", + "schema": { + "type": "string", + "description": "Response format. e.g. \"application/json\" (default), \"text/csv\",\n\"application/vnd.pgrst.object+json\" (singular-row mode)." + } + }, + { + "name": "Accept-Profile", + "in": "header", + "description": "Target a non-default schema exposed by PostgREST.", + "schema": { + "type": "string", + "description": "Target a non-default schema exposed by PostgREST." + } + }, + { + "name": "Prefer", + "in": "header", + "description": "Counting mode. e.g. \"count=exact\", \"count=planned\", \"count=estimated\".", + "schema": { + "type": "string", + "description": "Counting mode. e.g. \"count=exact\", \"count=planned\", \"count=estimated\"." + } + }, + { + "name": "Range", + "in": "header", + "description": "Range-based pagination \u2014 e.g. \"0-9\" (ten rows starting at 0).", + "schema": { + "type": "string", + "description": "Range-based pagination \u2014 e.g. \"0-9\" (ten rows starting at 0)." + } + }, + { + "name": "Range-Unit", + "in": "header", + "description": "Unit for the Range header. Defaults to \"items\".", + "schema": { + "type": "string", + "description": "Unit for the Range header. Defaults to \"items\"." + } + } + ], + "responses": { + "200": { + "description": "SelectRows 200 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "patch": { + "operationId": "UpdateRows", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "filters", + "in": "query", + "description": "Horizontal filters \u2014 rows matching these filters will be updated.\nKey: column name. Value: \"{operator}.{value}\" e.g. {\"id\": \"eq.5\"}.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Content-Profile", + "in": "header", + "schema": { + "type": "string" + } + }, + { + "name": "Prefer", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "UpdateRows 200 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "post": { + "operationId": "InsertRows", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "description": "Columns to select in the returned representation (requires return=representation).", + "schema": { + "type": "string", + "description": "Columns to select in the returned representation (requires return=representation)." + } + }, + { + "name": "columns", + "in": "query", + "description": "Restrict which columns may be populated (useful with CSV uploads).", + "schema": { + "type": "string", + "description": "Restrict which columns may be populated (useful with CSV uploads)." + } + }, + { + "name": "Content-Profile", + "in": "header", + "description": "Target a non-default schema for the write.", + "schema": { + "type": "string", + "description": "Target a non-default schema for the write." + } + }, + { + "name": "Prefer", + "in": "header", + "description": "Return behavior and conflict handling.\ne.g. \"return=representation\", \"return=minimal\" (default),\n \"return=headers-only\", \"resolution=merge-duplicates\".", + "schema": { + "type": "string", + "description": "Return behavior and conflict handling.\ne.g. \"return=representation\", \"return=minimal\" (default),\n \"return=headers-only\", \"resolution=merge-duplicates\"." + } + } + ], + "responses": { + "201": { + "description": "InsertRows 201 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "put": { + "operationId": "UpsertRows", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "on_conflict", + "in": "query", + "description": "Columns to match for conflict detection (if not the primary key).", + "schema": { + "type": "string", + "description": "Columns to match for conflict detection (if not the primary key)." + } + }, + { + "name": "filters", + "in": "query", + "description": "Horizontal filters \u2014 rows matching these filters will be upserted.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Content-Profile", + "in": "header", + "schema": { + "type": "string" + } + }, + { + "name": "Prefer", + "in": "header", + "description": "e.g. \"return=representation\", \"resolution=merge-duplicates\",\n \"resolution=ignore-duplicates\".", + "schema": { + "type": "string", + "description": "e.g. \"return=representation\", \"resolution=merge-duplicates\",\n \"resolution=ignore-duplicates\"." + } + } + ], + "responses": { + "200": { + "description": "UpsertRows 200 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "DatabaseErrorResponseContent": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "PostgreSQL error code (e.g. \"23505\") or PostgREST error code (e.g. \"PGRST301\")." + }, + "message": { + "type": "string", + "description": "Human-readable error message." + }, + "details": { + "type": "string", + "description": "Extra context \u2014 constraint name, offending column, etc." + }, + "hint": { + "type": "string", + "description": "Hint from PostgreSQL." + } + } + }, + "StringMap": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Generic string-to-string map \u2014 used for arbitrary query parameter collections\n(e.g. PostgREST filter params, RPC GET arguments)." + }, + "FilterOperator": { + "type": "string", + "description": "PostgREST column filter operators. Format a filter value as \"{operator}.{value}\", e.g. \"eq.5\". Prefix with \"not.\" to negate: \"not.eq.5\". For logical grouping use keys \"or\" / \"and\" in the filters map.", + "enum": [ + "eq", + "neq", + "lt", + "lte", + "gt", + "gte", + "like", + "ilike", + "match", + "imatch", + "is", + "isdistinct", + "in", + "cs", + "cd", + "ov", + "sl", + "sr", + "nxl", + "nxr", + "adj", + "fts", + "plfts", + "phfts", + "wfts" + ] + } + } + } +} \ No newline at end of file diff --git a/kiota-spike/generated/Functions/Functions/FunctionsRequestBuilder.cs b/kiota-spike/generated/Functions/Functions/FunctionsRequestBuilder.cs new file mode 100644 index 00000000..b130fe8e --- /dev/null +++ b/kiota-spike/generated/Functions/Functions/FunctionsRequestBuilder.cs @@ -0,0 +1,41 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions; +using Supabase.Functions.Kiota.Functions.V1; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System; +namespace Supabase.Functions.Kiota.Functions +{ + /// + /// Builds and executes requests for operations under \functions + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class FunctionsRequestBuilder : BaseRequestBuilder + { + /// The v1 property + public global::Supabase.Functions.Kiota.Functions.V1.V1RequestBuilder V1 + { + get => new global::Supabase.Functions.Kiota.Functions.V1.V1RequestBuilder(PathParameters, RequestAdapter); + } + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public FunctionsRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/functions", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public FunctionsRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/functions", rawUrl) + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Functions/Functions/V1/Item/WithFunctionNameItemRequestBuilder.cs b/kiota-spike/generated/Functions/Functions/V1/Item/WithFunctionNameItemRequestBuilder.cs new file mode 100644 index 00000000..b0ac44ac --- /dev/null +++ b/kiota-spike/generated/Functions/Functions/V1/Item/WithFunctionNameItemRequestBuilder.cs @@ -0,0 +1,367 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using Supabase.Functions.Kiota.Models; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Supabase.Functions.Kiota.Functions.V1.Item +{ + /// + /// Builds and executes requests for operations under \functions\v1\{functionName} + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithFunctionNameItemRequestBuilder : BaseRequestBuilder + { + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public WithFunctionNameItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/functions/v1/{functionName}{?query*}", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public WithFunctionNameItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/functions/v1/{functionName}{?query*}", rawUrl) + { + } + /// A + /// Binary request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task DeleteAsync(Stream body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task DeleteAsync(Stream body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToDeleteRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Functions.Kiota.Models.FunctionsErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task GetAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + var requestInfo = ToGetRequestInformation(requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Functions.Kiota.Models.FunctionsErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Binary request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PatchAsync(Stream body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PatchAsync(Stream body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPatchRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Functions.Kiota.Models.FunctionsErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Binary request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PostAsync(Stream body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PostAsync(Stream body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPostRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Functions.Kiota.Models.FunctionsErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Binary request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PutAsync(Stream body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PutAsync(Stream body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPutRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Functions.Kiota.Models.FunctionsErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Binary request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToDeleteRequestInformation(Stream body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToDeleteRequestInformation(Stream body, Action> requestConfiguration = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.DELETE, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/octet-stream, application/json"); + requestInfo.SetStreamContent(body, "application/octet-stream"); + return requestInfo; + } + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToGetRequestInformation(Action> requestConfiguration = default) + { +#endif + var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/octet-stream, application/json"); + return requestInfo; + } + /// A + /// Binary request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPatchRequestInformation(Stream body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPatchRequestInformation(Stream body, Action> requestConfiguration = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.PATCH, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/octet-stream, application/json"); + requestInfo.SetStreamContent(body, "application/octet-stream"); + return requestInfo; + } + /// A + /// Binary request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPostRequestInformation(Stream body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPostRequestInformation(Stream body, Action> requestConfiguration = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.POST, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/octet-stream, application/json"); + requestInfo.SetStreamContent(body, "application/octet-stream"); + return requestInfo; + } + /// A + /// Binary request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPutRequestInformation(Stream body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPutRequestInformation(Stream body, Action> requestConfiguration = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.PUT, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/octet-stream, application/json"); + requestInfo.SetStreamContent(body, "application/octet-stream"); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Supabase.Functions.Kiota.Functions.V1.Item.WithFunctionNameItemRequestBuilder WithUrl(string rawUrl) + { + return new global::Supabase.Functions.Kiota.Functions.V1.Item.WithFunctionNameItemRequestBuilder(rawUrl, RequestAdapter); + } + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class WithFunctionNameItemRequestBuilderDeleteQueryParameters + #pragma warning restore CS1591 + { + /// Arbitrary query parameters appended to the function URL.Corresponds to FunctionInvokeOptions.query. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("query")] + public string? Query { get; set; } +#nullable restore +#else + [QueryParameter("query")] + public string Query { get; set; } +#endif + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithFunctionNameItemRequestBuilderDeleteRequestConfiguration : RequestConfiguration + { + } + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class WithFunctionNameItemRequestBuilderGetQueryParameters + #pragma warning restore CS1591 + { + /// Arbitrary query parameters appended to the function URL.Corresponds to FunctionInvokeOptions.query. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("query")] + public string? Query { get; set; } +#nullable restore +#else + [QueryParameter("query")] + public string Query { get; set; } +#endif + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithFunctionNameItemRequestBuilderGetRequestConfiguration : RequestConfiguration + { + } + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class WithFunctionNameItemRequestBuilderPatchQueryParameters + #pragma warning restore CS1591 + { + /// Arbitrary query parameters appended to the function URL.Corresponds to FunctionInvokeOptions.query. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("query")] + public string? Query { get; set; } +#nullable restore +#else + [QueryParameter("query")] + public string Query { get; set; } +#endif + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithFunctionNameItemRequestBuilderPatchRequestConfiguration : RequestConfiguration + { + } + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class WithFunctionNameItemRequestBuilderPostQueryParameters + #pragma warning restore CS1591 + { + /// Arbitrary query parameters appended to the function URL.Corresponds to FunctionInvokeOptions.query. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("query")] + public string? Query { get; set; } +#nullable restore +#else + [QueryParameter("query")] + public string Query { get; set; } +#endif + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithFunctionNameItemRequestBuilderPostRequestConfiguration : RequestConfiguration + { + } + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class WithFunctionNameItemRequestBuilderPutQueryParameters + #pragma warning restore CS1591 + { + /// Arbitrary query parameters appended to the function URL.Corresponds to FunctionInvokeOptions.query. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("query")] + public string? Query { get; set; } +#nullable restore +#else + [QueryParameter("query")] + public string Query { get; set; } +#endif + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithFunctionNameItemRequestBuilderPutRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Functions/Functions/V1/V1RequestBuilder.cs b/kiota-spike/generated/Functions/Functions/V1/V1RequestBuilder.cs new file mode 100644 index 00000000..d71826c6 --- /dev/null +++ b/kiota-spike/generated/Functions/Functions/V1/V1RequestBuilder.cs @@ -0,0 +1,48 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions; +using Supabase.Functions.Kiota.Functions.V1.Item; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System; +namespace Supabase.Functions.Kiota.Functions.V1 +{ + /// + /// Builds and executes requests for operations under \functions\v1 + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class V1RequestBuilder : BaseRequestBuilder + { + /// Gets an item from the Supabase.Functions.Kiota.functions.v1.item collection + /// Unique identifier of the item + /// A + public global::Supabase.Functions.Kiota.Functions.V1.Item.WithFunctionNameItemRequestBuilder this[string position] + { + get + { + var urlTplParams = new Dictionary(PathParameters); + urlTplParams.Add("functionName", position); + return new global::Supabase.Functions.Kiota.Functions.V1.Item.WithFunctionNameItemRequestBuilder(urlTplParams, RequestAdapter); + } + } + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public V1RequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/functions/v1", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public V1RequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/functions/v1", rawUrl) + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Functions/FunctionsApiClient.cs b/kiota-spike/generated/Functions/FunctionsApiClient.cs new file mode 100644 index 00000000..0567a030 --- /dev/null +++ b/kiota-spike/generated/Functions/FunctionsApiClient.cs @@ -0,0 +1,43 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions; +using Microsoft.Kiota.Serialization.Form; +using Microsoft.Kiota.Serialization.Json; +using Microsoft.Kiota.Serialization.Multipart; +using Microsoft.Kiota.Serialization.Text; +using Supabase.Functions.Kiota.Functions; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System; +namespace Supabase.Functions.Kiota +{ + /// + /// The main entry point of the SDK, exposes the configuration and the fluent API. + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class FunctionsApiClient : BaseRequestBuilder + { + /// The functions property + public global::Supabase.Functions.Kiota.Functions.FunctionsRequestBuilder Functions + { + get => new global::Supabase.Functions.Kiota.Functions.FunctionsRequestBuilder(PathParameters, RequestAdapter); + } + /// + /// Instantiates a new and sets the default values. + /// + /// The request adapter to use to execute the requests. + public FunctionsApiClient(IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}", new Dictionary()) + { + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultDeserializer(); + ApiClientBuilder.RegisterDefaultDeserializer(); + ApiClientBuilder.RegisterDefaultDeserializer(); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Functions/Models/FunctionsErrorResponseContent.cs b/kiota-spike/generated/Functions/Models/FunctionsErrorResponseContent.cs new file mode 100644 index 00000000..e8e41480 --- /dev/null +++ b/kiota-spike/generated/Functions/Models/FunctionsErrorResponseContent.cs @@ -0,0 +1,68 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Functions.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class FunctionsErrorResponseContent : ApiException, IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// The primary error message. + public override string Message { get => MessageEscaped ?? string.Empty; } + /// The message property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? MessageEscaped { get; set; } +#nullable restore +#else + public string MessageEscaped { get; set; } +#endif + /// + /// Instantiates a new and sets the default values. + /// + public FunctionsErrorResponseContent() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Functions.Kiota.Models.FunctionsErrorResponseContent CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Functions.Kiota.Models.FunctionsErrorResponseContent(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "message", n => { MessageEscaped = n.GetStringValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("message", MessageEscaped); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Functions/kiota-lock.json b/kiota-spike/generated/Functions/kiota-lock.json new file mode 100644 index 00000000..b4389cd1 --- /dev/null +++ b/kiota-spike/generated/Functions/kiota-lock.json @@ -0,0 +1,34 @@ +{ + "descriptionHash": "C27FE6DB0936035F04FB0D93642C9730C77B5BFBA086BE5B8561C22E6305492EDD7C627EBFD26F6A7FE22AA4B33DE38EE04B43DC072544C39499F039DBC56F19", + "descriptionLocation": "../FunctionsService.ready.json", + "lockFileVersion": "1.0.0", + "kiotaVersion": "1.32.4", + "clientClassName": "FunctionsApiClient", + "typeAccessModifier": "Public", + "clientNamespaceName": "Supabase.Functions.Kiota", + "language": "CSharp", + "usesBackingStore": false, + "excludeBackwardCompatible": false, + "includeAdditionalData": true, + "disableSSLValidation": false, + "serializers": [ + "Microsoft.Kiota.Serialization.Json.JsonSerializationWriterFactory", + "Microsoft.Kiota.Serialization.Text.TextSerializationWriterFactory", + "Microsoft.Kiota.Serialization.Form.FormSerializationWriterFactory", + "Microsoft.Kiota.Serialization.Multipart.MultipartSerializationWriterFactory" + ], + "deserializers": [ + "Microsoft.Kiota.Serialization.Json.JsonParseNodeFactory", + "Microsoft.Kiota.Serialization.Text.TextParseNodeFactory", + "Microsoft.Kiota.Serialization.Form.FormParseNodeFactory" + ], + "structuredMimeTypes": [ + "application/json", + "text/plain;q=0.9", + "application/x-www-form-urlencoded;q=0.2", + "multipart/form-data;q=0.1" + ], + "includePatterns": [], + "excludePatterns": [], + "disabledValidationRules": [] +} \ No newline at end of file diff --git a/kiota-spike/generated/FunctionsService.ready.json b/kiota-spike/generated/FunctionsService.ready.json new file mode 100644 index 00000000..57295bb6 --- /dev/null +++ b/kiota-spike/generated/FunctionsService.ready.json @@ -0,0 +1,330 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Supabase Functions API", + "version": "1.0" + }, + "paths": { + "/functions/v1/{functionName}": { + "delete": { + "operationId": "InvokeFunctionDelete", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionDelete 200 response", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + }, + "get": { + "operationId": "InvokeFunctionGet", + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionGet 200 response", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + }, + "patch": { + "operationId": "InvokeFunctionPatch", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionPatch 200 response", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + }, + "post": { + "operationId": "InvokeFunctionPost", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionPost 200 response", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + }, + "put": { + "operationId": "InvokeFunctionPut", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionPut 200 response", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "FunctionsErrorResponseContent": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + }, + "StringMap": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Generic string-to-string map \u2014 used for arbitrary query parameter collections\n(e.g. PostgREST filter params, RPC GET arguments)." + } + } + } +} \ No newline at end of file diff --git a/kiota-spike/generated/Storage/Bucket/BucketRequestBuilder.cs b/kiota-spike/generated/Storage/Bucket/BucketRequestBuilder.cs new file mode 100644 index 00000000..cfb526a5 --- /dev/null +++ b/kiota-spike/generated/Storage/Bucket/BucketRequestBuilder.cs @@ -0,0 +1,154 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.Bucket.Item; +using Supabase.Storage.Kiota.Models; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Supabase.Storage.Kiota.Bucket +{ + /// + /// Builds and executes requests for operations under \bucket + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class BucketRequestBuilder : BaseRequestBuilder + { + /// Gets an item from the Supabase.Storage.Kiota.bucket.item collection + /// Unique identifier of the item + /// A + public global::Supabase.Storage.Kiota.Bucket.Item.BucketItemRequestBuilder this[string position] + { + get + { + var urlTplParams = new Dictionary(PathParameters); + urlTplParams.Add("id", position); + return new global::Supabase.Storage.Kiota.Bucket.Item.BucketItemRequestBuilder(urlTplParams, RequestAdapter); + } + } + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public BucketRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/bucket", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public BucketRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/bucket", rawUrl) + { + } + /// A List<global::Supabase.Storage.Kiota.Models.Bucket> + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task?> GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task> GetAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + var requestInfo = ToGetRequestInformation(requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + var collectionResult = await RequestAdapter.SendCollectionAsync(requestInfo, global::Supabase.Storage.Kiota.Models.Bucket.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false); + return collectionResult?.AsList(); + } + /// A + /// The request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PostAsync(global::Supabase.Storage.Kiota.Models.CreateBucketRequestContent body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PostAsync(global::Supabase.Storage.Kiota.Models.CreateBucketRequestContent body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPostRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToGetRequestInformation(Action> requestConfiguration = default) + { +#endif + var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + return requestInfo; + } + /// A + /// The request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPostRequestInformation(global::Supabase.Storage.Kiota.Models.CreateBucketRequestContent body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPostRequestInformation(global::Supabase.Storage.Kiota.Models.CreateBucketRequestContent body, Action> requestConfiguration = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.POST, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + requestInfo.SetContentFromParsable(RequestAdapter, "application/json", body); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Supabase.Storage.Kiota.Bucket.BucketRequestBuilder WithUrl(string rawUrl) + { + return new global::Supabase.Storage.Kiota.Bucket.BucketRequestBuilder(rawUrl, RequestAdapter); + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class BucketRequestBuilderGetRequestConfiguration : RequestConfiguration + { + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class BucketRequestBuilderPostRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Bucket/Item/BucketItemRequestBuilder.cs b/kiota-spike/generated/Storage/Bucket/Item/BucketItemRequestBuilder.cs new file mode 100644 index 00000000..31c7e916 --- /dev/null +++ b/kiota-spike/generated/Storage/Bucket/Item/BucketItemRequestBuilder.cs @@ -0,0 +1,190 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.Bucket.Item.Empty; +using Supabase.Storage.Kiota.Models; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Supabase.Storage.Kiota.Bucket.Item +{ + /// + /// Builds and executes requests for operations under \bucket\{id} + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class BucketItemRequestBuilder : BaseRequestBuilder + { + /// The empty property + public global::Supabase.Storage.Kiota.Bucket.Item.Empty.EmptyRequestBuilder Empty + { + get => new global::Supabase.Storage.Kiota.Bucket.Item.Empty.EmptyRequestBuilder(PathParameters, RequestAdapter); + } + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public BucketItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/bucket/{id}", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public BucketItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/bucket/{id}", rawUrl) + { + } + /// A + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task DeleteAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task DeleteAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + var requestInfo = ToDeleteRequestInformation(requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task GetAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + var requestInfo = ToGetRequestInformation(requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendAsync(requestInfo, global::Supabase.Storage.Kiota.Models.GetBucketResponseContent.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// The request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PutAsync(global::Supabase.Storage.Kiota.Models.UpdateBucketRequestContent body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PutAsync(global::Supabase.Storage.Kiota.Models.UpdateBucketRequestContent body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPutRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToDeleteRequestInformation(Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToDeleteRequestInformation(Action> requestConfiguration = default) + { +#endif + var requestInfo = new RequestInformation(Method.DELETE, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + return requestInfo; + } + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToGetRequestInformation(Action> requestConfiguration = default) + { +#endif + var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + return requestInfo; + } + /// A + /// The request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPutRequestInformation(global::Supabase.Storage.Kiota.Models.UpdateBucketRequestContent body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPutRequestInformation(global::Supabase.Storage.Kiota.Models.UpdateBucketRequestContent body, Action> requestConfiguration = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.PUT, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + requestInfo.SetContentFromParsable(RequestAdapter, "application/json", body); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Supabase.Storage.Kiota.Bucket.Item.BucketItemRequestBuilder WithUrl(string rawUrl) + { + return new global::Supabase.Storage.Kiota.Bucket.Item.BucketItemRequestBuilder(rawUrl, RequestAdapter); + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class BucketItemRequestBuilderDeleteRequestConfiguration : RequestConfiguration + { + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class BucketItemRequestBuilderGetRequestConfiguration : RequestConfiguration + { + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class BucketItemRequestBuilderPutRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Bucket/Item/Empty/EmptyRequestBuilder.cs b/kiota-spike/generated/Storage/Bucket/Item/Empty/EmptyRequestBuilder.cs new file mode 100644 index 00000000..d81c7d3a --- /dev/null +++ b/kiota-spike/generated/Storage/Bucket/Item/Empty/EmptyRequestBuilder.cs @@ -0,0 +1,91 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.Models; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Supabase.Storage.Kiota.Bucket.Item.Empty +{ + /// + /// Builds and executes requests for operations under \bucket\{id}\empty + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class EmptyRequestBuilder : BaseRequestBuilder + { + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public EmptyRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/bucket/{id}/empty", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public EmptyRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/bucket/{id}/empty", rawUrl) + { + } + /// A + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PostAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PostAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + var requestInfo = ToPostRequestInformation(requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPostRequestInformation(Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPostRequestInformation(Action> requestConfiguration = default) + { +#endif + var requestInfo = new RequestInformation(Method.POST, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Supabase.Storage.Kiota.Bucket.Item.Empty.EmptyRequestBuilder WithUrl(string rawUrl) + { + return new global::Supabase.Storage.Kiota.Bucket.Item.Empty.EmptyRequestBuilder(rawUrl, RequestAdapter); + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class EmptyRequestBuilderPostRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/Bucket.cs b/kiota-spike/generated/Storage/Models/Bucket.cs new file mode 100644 index 00000000..337885c7 --- /dev/null +++ b/kiota-spike/generated/Storage/Models/Bucket.cs @@ -0,0 +1,113 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class Bucket : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// Common string list shape reused across services. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public List? AllowedMimeTypes { get; set; } +#nullable restore +#else + public List AllowedMimeTypes { get; set; } +#endif + /// The created_at property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? CreatedAt { get; set; } +#nullable restore +#else + public string CreatedAt { get; set; } +#endif + /// The file_size_limit property + public double? FileSizeLimit { get; set; } + /// The id property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Id { get; set; } +#nullable restore +#else + public string Id { get; set; } +#endif + /// The name property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Name { get; set; } +#nullable restore +#else + public string Name { get; set; } +#endif + /// The public property + public bool? Public { get; set; } + /// The updated_at property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? UpdatedAt { get; set; } +#nullable restore +#else + public string UpdatedAt { get; set; } +#endif + /// + /// Instantiates a new and sets the default values. + /// + public Bucket() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.Bucket CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.Bucket(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "allowed_mime_types", n => { AllowedMimeTypes = n.GetCollectionOfPrimitiveValues()?.AsList(); } }, + { "created_at", n => { CreatedAt = n.GetStringValue(); } }, + { "file_size_limit", n => { FileSizeLimit = n.GetDoubleValue(); } }, + { "id", n => { Id = n.GetStringValue(); } }, + { "name", n => { Name = n.GetStringValue(); } }, + { "public", n => { Public = n.GetBoolValue(); } }, + { "updated_at", n => { UpdatedAt = n.GetStringValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteCollectionOfPrimitiveValues("allowed_mime_types", AllowedMimeTypes); + writer.WriteStringValue("created_at", CreatedAt); + writer.WriteDoubleValue("file_size_limit", FileSizeLimit); + writer.WriteStringValue("id", Id); + writer.WriteStringValue("name", Name); + writer.WriteBoolValue("public", Public); + writer.WriteStringValue("updated_at", UpdatedAt); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/CopyObjectRequestContent.cs b/kiota-spike/generated/Storage/Models/CopyObjectRequestContent.cs new file mode 100644 index 00000000..627beab3 --- /dev/null +++ b/kiota-spike/generated/Storage/Models/CopyObjectRequestContent.cs @@ -0,0 +1,95 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class CopyObjectRequestContent : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// The bucketId property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? BucketId { get; set; } +#nullable restore +#else + public string BucketId { get; set; } +#endif + /// The destinationBucket property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? DestinationBucket { get; set; } +#nullable restore +#else + public string DestinationBucket { get; set; } +#endif + /// The destinationKey property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? DestinationKey { get; set; } +#nullable restore +#else + public string DestinationKey { get; set; } +#endif + /// The sourceKey property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? SourceKey { get; set; } +#nullable restore +#else + public string SourceKey { get; set; } +#endif + /// + /// Instantiates a new and sets the default values. + /// + public CopyObjectRequestContent() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.CopyObjectRequestContent CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.CopyObjectRequestContent(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "bucketId", n => { BucketId = n.GetStringValue(); } }, + { "destinationBucket", n => { DestinationBucket = n.GetStringValue(); } }, + { "destinationKey", n => { DestinationKey = n.GetStringValue(); } }, + { "sourceKey", n => { SourceKey = n.GetStringValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("bucketId", BucketId); + writer.WriteStringValue("destinationBucket", DestinationBucket); + writer.WriteStringValue("destinationKey", DestinationKey); + writer.WriteStringValue("sourceKey", SourceKey); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/CopyObjectResponseContent.cs b/kiota-spike/generated/Storage/Models/CopyObjectResponseContent.cs new file mode 100644 index 00000000..194cdab3 --- /dev/null +++ b/kiota-spike/generated/Storage/Models/CopyObjectResponseContent.cs @@ -0,0 +1,65 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class CopyObjectResponseContent : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// The Key property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Key { get; set; } +#nullable restore +#else + public string Key { get; set; } +#endif + /// + /// Instantiates a new and sets the default values. + /// + public CopyObjectResponseContent() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.CopyObjectResponseContent CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.CopyObjectResponseContent(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "Key", n => { Key = n.GetStringValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("Key", Key); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/CreateBucketRequestContent.cs b/kiota-spike/generated/Storage/Models/CreateBucketRequestContent.cs new file mode 100644 index 00000000..b3750931 --- /dev/null +++ b/kiota-spike/generated/Storage/Models/CreateBucketRequestContent.cs @@ -0,0 +1,93 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class CreateBucketRequestContent : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// Common string list shape reused across services. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public List? AllowedMimeTypes { get; set; } +#nullable restore +#else + public List AllowedMimeTypes { get; set; } +#endif + /// The file_size_limit property + public double? FileSizeLimit { get; set; } + /// The id property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Id { get; set; } +#nullable restore +#else + public string Id { get; set; } +#endif + /// The name property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Name { get; set; } +#nullable restore +#else + public string Name { get; set; } +#endif + /// The public property + public bool? Public { get; set; } + /// + /// Instantiates a new and sets the default values. + /// + public CreateBucketRequestContent() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.CreateBucketRequestContent CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.CreateBucketRequestContent(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "allowed_mime_types", n => { AllowedMimeTypes = n.GetCollectionOfPrimitiveValues()?.AsList(); } }, + { "file_size_limit", n => { FileSizeLimit = n.GetDoubleValue(); } }, + { "id", n => { Id = n.GetStringValue(); } }, + { "name", n => { Name = n.GetStringValue(); } }, + { "public", n => { Public = n.GetBoolValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteCollectionOfPrimitiveValues("allowed_mime_types", AllowedMimeTypes); + writer.WriteDoubleValue("file_size_limit", FileSizeLimit); + writer.WriteStringValue("id", Id); + writer.WriteStringValue("name", Name); + writer.WriteBoolValue("public", Public); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/CreateSignedUploadUrlResponseContent.cs b/kiota-spike/generated/Storage/Models/CreateSignedUploadUrlResponseContent.cs new file mode 100644 index 00000000..f3025964 --- /dev/null +++ b/kiota-spike/generated/Storage/Models/CreateSignedUploadUrlResponseContent.cs @@ -0,0 +1,65 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class CreateSignedUploadUrlResponseContent : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// The url property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Url { get; set; } +#nullable restore +#else + public string Url { get; set; } +#endif + /// + /// Instantiates a new and sets the default values. + /// + public CreateSignedUploadUrlResponseContent() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.CreateSignedUploadUrlResponseContent CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.CreateSignedUploadUrlResponseContent(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "url", n => { Url = n.GetStringValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("url", Url); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/CreateSignedUrlRequestContent.cs b/kiota-spike/generated/Storage/Models/CreateSignedUrlRequestContent.cs new file mode 100644 index 00000000..d0feccae --- /dev/null +++ b/kiota-spike/generated/Storage/Models/CreateSignedUrlRequestContent.cs @@ -0,0 +1,59 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class CreateSignedUrlRequestContent : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// The expiresIn property + public double? ExpiresIn { get; set; } + /// + /// Instantiates a new and sets the default values. + /// + public CreateSignedUrlRequestContent() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.CreateSignedUrlRequestContent CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.CreateSignedUrlRequestContent(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "expiresIn", n => { ExpiresIn = n.GetDoubleValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteDoubleValue("expiresIn", ExpiresIn); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/CreateSignedUrlResponseContent.cs b/kiota-spike/generated/Storage/Models/CreateSignedUrlResponseContent.cs new file mode 100644 index 00000000..e5963b84 --- /dev/null +++ b/kiota-spike/generated/Storage/Models/CreateSignedUrlResponseContent.cs @@ -0,0 +1,65 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class CreateSignedUrlResponseContent : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// The signedURL property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? SignedURL { get; set; } +#nullable restore +#else + public string SignedURL { get; set; } +#endif + /// + /// Instantiates a new and sets the default values. + /// + public CreateSignedUrlResponseContent() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.CreateSignedUrlResponseContent CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.CreateSignedUrlResponseContent(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "signedURL", n => { SignedURL = n.GetStringValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("signedURL", SignedURL); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/CreateSignedUrlsRequestContent.cs b/kiota-spike/generated/Storage/Models/CreateSignedUrlsRequestContent.cs new file mode 100644 index 00000000..ef2bca59 --- /dev/null +++ b/kiota-spike/generated/Storage/Models/CreateSignedUrlsRequestContent.cs @@ -0,0 +1,69 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class CreateSignedUrlsRequestContent : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// The expiresIn property + public double? ExpiresIn { get; set; } + /// Common string list shape reused across services. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public List? Paths { get; set; } +#nullable restore +#else + public List Paths { get; set; } +#endif + /// + /// Instantiates a new and sets the default values. + /// + public CreateSignedUrlsRequestContent() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.CreateSignedUrlsRequestContent CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.CreateSignedUrlsRequestContent(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "expiresIn", n => { ExpiresIn = n.GetDoubleValue(); } }, + { "paths", n => { Paths = n.GetCollectionOfPrimitiveValues()?.AsList(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteDoubleValue("expiresIn", ExpiresIn); + writer.WriteCollectionOfPrimitiveValues("paths", Paths); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/DeleteObjectsRequestContent.cs b/kiota-spike/generated/Storage/Models/DeleteObjectsRequestContent.cs new file mode 100644 index 00000000..d59d39b4 --- /dev/null +++ b/kiota-spike/generated/Storage/Models/DeleteObjectsRequestContent.cs @@ -0,0 +1,65 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class DeleteObjectsRequestContent : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// Common string list shape reused across services. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public List? Prefixes { get; set; } +#nullable restore +#else + public List Prefixes { get; set; } +#endif + /// + /// Instantiates a new and sets the default values. + /// + public DeleteObjectsRequestContent() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.DeleteObjectsRequestContent CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.DeleteObjectsRequestContent(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "prefixes", n => { Prefixes = n.GetCollectionOfPrimitiveValues()?.AsList(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteCollectionOfPrimitiveValues("prefixes", Prefixes); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/FileMetadata.cs b/kiota-spike/generated/Storage/Models/FileMetadata.cs new file mode 100644 index 00000000..af15b7b5 --- /dev/null +++ b/kiota-spike/generated/Storage/Models/FileMetadata.cs @@ -0,0 +1,107 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class FileMetadata : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// The cacheControl property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? CacheControl { get; set; } +#nullable restore +#else + public string CacheControl { get; set; } +#endif + /// The contentLength property + public double? ContentLength { get; set; } + /// The eTag property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? ETag { get; set; } +#nullable restore +#else + public string ETag { get; set; } +#endif + /// The httpStatusCode property + public double? HttpStatusCode { get; set; } + /// The lastModified property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? LastModified { get; set; } +#nullable restore +#else + public string LastModified { get; set; } +#endif + /// The mimetype property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Mimetype { get; set; } +#nullable restore +#else + public string Mimetype { get; set; } +#endif + /// The size property + public double? Size { get; set; } + /// + /// Instantiates a new and sets the default values. + /// + public FileMetadata() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.FileMetadata CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.FileMetadata(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "cacheControl", n => { CacheControl = n.GetStringValue(); } }, + { "contentLength", n => { ContentLength = n.GetDoubleValue(); } }, + { "eTag", n => { ETag = n.GetStringValue(); } }, + { "httpStatusCode", n => { HttpStatusCode = n.GetDoubleValue(); } }, + { "lastModified", n => { LastModified = n.GetStringValue(); } }, + { "mimetype", n => { Mimetype = n.GetStringValue(); } }, + { "size", n => { Size = n.GetDoubleValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("cacheControl", CacheControl); + writer.WriteDoubleValue("contentLength", ContentLength); + writer.WriteStringValue("eTag", ETag); + writer.WriteDoubleValue("httpStatusCode", HttpStatusCode); + writer.WriteStringValue("lastModified", LastModified); + writer.WriteStringValue("mimetype", Mimetype); + writer.WriteDoubleValue("size", Size); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/FileObject.cs b/kiota-spike/generated/Storage/Models/FileObject.cs new file mode 100644 index 00000000..57d36c72 --- /dev/null +++ b/kiota-spike/generated/Storage/Models/FileObject.cs @@ -0,0 +1,115 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class FileObject : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// The created_at property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? CreatedAt { get; set; } +#nullable restore +#else + public string CreatedAt { get; set; } +#endif + /// The id property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Id { get; set; } +#nullable restore +#else + public string Id { get; set; } +#endif + /// The last_accessed_at property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? LastAccessedAt { get; set; } +#nullable restore +#else + public string LastAccessedAt { get; set; } +#endif + /// The metadata property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public global::Supabase.Storage.Kiota.Models.FileMetadata? Metadata { get; set; } +#nullable restore +#else + public global::Supabase.Storage.Kiota.Models.FileMetadata Metadata { get; set; } +#endif + /// The name property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Name { get; set; } +#nullable restore +#else + public string Name { get; set; } +#endif + /// The updated_at property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? UpdatedAt { get; set; } +#nullable restore +#else + public string UpdatedAt { get; set; } +#endif + /// + /// Instantiates a new and sets the default values. + /// + public FileObject() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.FileObject CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.FileObject(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "created_at", n => { CreatedAt = n.GetStringValue(); } }, + { "id", n => { Id = n.GetStringValue(); } }, + { "last_accessed_at", n => { LastAccessedAt = n.GetStringValue(); } }, + { "metadata", n => { Metadata = n.GetObjectValue(global::Supabase.Storage.Kiota.Models.FileMetadata.CreateFromDiscriminatorValue); } }, + { "name", n => { Name = n.GetStringValue(); } }, + { "updated_at", n => { UpdatedAt = n.GetStringValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("created_at", CreatedAt); + writer.WriteStringValue("id", Id); + writer.WriteStringValue("last_accessed_at", LastAccessedAt); + writer.WriteObjectValue("metadata", Metadata); + writer.WriteStringValue("name", Name); + writer.WriteStringValue("updated_at", UpdatedAt); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/GetBucketResponseContent.cs b/kiota-spike/generated/Storage/Models/GetBucketResponseContent.cs new file mode 100644 index 00000000..20d71801 --- /dev/null +++ b/kiota-spike/generated/Storage/Models/GetBucketResponseContent.cs @@ -0,0 +1,113 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class GetBucketResponseContent : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// Common string list shape reused across services. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public List? AllowedMimeTypes { get; set; } +#nullable restore +#else + public List AllowedMimeTypes { get; set; } +#endif + /// The created_at property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? CreatedAt { get; set; } +#nullable restore +#else + public string CreatedAt { get; set; } +#endif + /// The file_size_limit property + public double? FileSizeLimit { get; set; } + /// The id property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Id { get; set; } +#nullable restore +#else + public string Id { get; set; } +#endif + /// The name property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Name { get; set; } +#nullable restore +#else + public string Name { get; set; } +#endif + /// The public property + public bool? Public { get; set; } + /// The updated_at property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? UpdatedAt { get; set; } +#nullable restore +#else + public string UpdatedAt { get; set; } +#endif + /// + /// Instantiates a new and sets the default values. + /// + public GetBucketResponseContent() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.GetBucketResponseContent CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.GetBucketResponseContent(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "allowed_mime_types", n => { AllowedMimeTypes = n.GetCollectionOfPrimitiveValues()?.AsList(); } }, + { "created_at", n => { CreatedAt = n.GetStringValue(); } }, + { "file_size_limit", n => { FileSizeLimit = n.GetDoubleValue(); } }, + { "id", n => { Id = n.GetStringValue(); } }, + { "name", n => { Name = n.GetStringValue(); } }, + { "public", n => { Public = n.GetBoolValue(); } }, + { "updated_at", n => { UpdatedAt = n.GetStringValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteCollectionOfPrimitiveValues("allowed_mime_types", AllowedMimeTypes); + writer.WriteStringValue("created_at", CreatedAt); + writer.WriteDoubleValue("file_size_limit", FileSizeLimit); + writer.WriteStringValue("id", Id); + writer.WriteStringValue("name", Name); + writer.WriteBoolValue("public", Public); + writer.WriteStringValue("updated_at", UpdatedAt); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/GetObjectInfoResponseContent.cs b/kiota-spike/generated/Storage/Models/GetObjectInfoResponseContent.cs new file mode 100644 index 00000000..34e6bf68 --- /dev/null +++ b/kiota-spike/generated/Storage/Models/GetObjectInfoResponseContent.cs @@ -0,0 +1,107 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class GetObjectInfoResponseContent : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// The cacheControl property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? CacheControl { get; set; } +#nullable restore +#else + public string CacheControl { get; set; } +#endif + /// The contentLength property + public double? ContentLength { get; set; } + /// The eTag property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? ETag { get; set; } +#nullable restore +#else + public string ETag { get; set; } +#endif + /// The httpStatusCode property + public double? HttpStatusCode { get; set; } + /// The lastModified property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? LastModified { get; set; } +#nullable restore +#else + public string LastModified { get; set; } +#endif + /// The mimetype property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Mimetype { get; set; } +#nullable restore +#else + public string Mimetype { get; set; } +#endif + /// The size property + public double? Size { get; set; } + /// + /// Instantiates a new and sets the default values. + /// + public GetObjectInfoResponseContent() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.GetObjectInfoResponseContent CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.GetObjectInfoResponseContent(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "cacheControl", n => { CacheControl = n.GetStringValue(); } }, + { "contentLength", n => { ContentLength = n.GetDoubleValue(); } }, + { "eTag", n => { ETag = n.GetStringValue(); } }, + { "httpStatusCode", n => { HttpStatusCode = n.GetDoubleValue(); } }, + { "lastModified", n => { LastModified = n.GetStringValue(); } }, + { "mimetype", n => { Mimetype = n.GetStringValue(); } }, + { "size", n => { Size = n.GetDoubleValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("cacheControl", CacheControl); + writer.WriteDoubleValue("contentLength", ContentLength); + writer.WriteStringValue("eTag", ETag); + writer.WriteDoubleValue("httpStatusCode", HttpStatusCode); + writer.WriteStringValue("lastModified", LastModified); + writer.WriteStringValue("mimetype", Mimetype); + writer.WriteDoubleValue("size", Size); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/ListObjectsRequestContent.cs b/kiota-spike/generated/Storage/Models/ListObjectsRequestContent.cs new file mode 100644 index 00000000..852ff9db --- /dev/null +++ b/kiota-spike/generated/Storage/Models/ListObjectsRequestContent.cs @@ -0,0 +1,83 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class ListObjectsRequestContent : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// The limit property + public double? Limit { get; set; } + /// The offset property + public double? Offset { get; set; } + /// The prefix property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Prefix { get; set; } +#nullable restore +#else + public string Prefix { get; set; } +#endif + /// The sortBy property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public global::Supabase.Storage.Kiota.Models.SortBy? SortBy { get; set; } +#nullable restore +#else + public global::Supabase.Storage.Kiota.Models.SortBy SortBy { get; set; } +#endif + /// + /// Instantiates a new and sets the default values. + /// + public ListObjectsRequestContent() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.ListObjectsRequestContent CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.ListObjectsRequestContent(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "limit", n => { Limit = n.GetDoubleValue(); } }, + { "offset", n => { Offset = n.GetDoubleValue(); } }, + { "prefix", n => { Prefix = n.GetStringValue(); } }, + { "sortBy", n => { SortBy = n.GetObjectValue(global::Supabase.Storage.Kiota.Models.SortBy.CreateFromDiscriminatorValue); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteDoubleValue("limit", Limit); + writer.WriteDoubleValue("offset", Offset); + writer.WriteStringValue("prefix", Prefix); + writer.WriteObjectValue("sortBy", SortBy); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/MoveObjectRequestContent.cs b/kiota-spike/generated/Storage/Models/MoveObjectRequestContent.cs new file mode 100644 index 00000000..234685fe --- /dev/null +++ b/kiota-spike/generated/Storage/Models/MoveObjectRequestContent.cs @@ -0,0 +1,95 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class MoveObjectRequestContent : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// The bucketId property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? BucketId { get; set; } +#nullable restore +#else + public string BucketId { get; set; } +#endif + /// The destinationBucket property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? DestinationBucket { get; set; } +#nullable restore +#else + public string DestinationBucket { get; set; } +#endif + /// The destinationKey property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? DestinationKey { get; set; } +#nullable restore +#else + public string DestinationKey { get; set; } +#endif + /// The sourceKey property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? SourceKey { get; set; } +#nullable restore +#else + public string SourceKey { get; set; } +#endif + /// + /// Instantiates a new and sets the default values. + /// + public MoveObjectRequestContent() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.MoveObjectRequestContent CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.MoveObjectRequestContent(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "bucketId", n => { BucketId = n.GetStringValue(); } }, + { "destinationBucket", n => { DestinationBucket = n.GetStringValue(); } }, + { "destinationKey", n => { DestinationKey = n.GetStringValue(); } }, + { "sourceKey", n => { SourceKey = n.GetStringValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("bucketId", BucketId); + writer.WriteStringValue("destinationBucket", DestinationBucket); + writer.WriteStringValue("destinationKey", DestinationKey); + writer.WriteStringValue("sourceKey", SourceKey); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/SignedUrlResult.cs b/kiota-spike/generated/Storage/Models/SignedUrlResult.cs new file mode 100644 index 00000000..0fe8a5ee --- /dev/null +++ b/kiota-spike/generated/Storage/Models/SignedUrlResult.cs @@ -0,0 +1,85 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class SignedUrlResult : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// The error property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Error { get; set; } +#nullable restore +#else + public string Error { get; set; } +#endif + /// The path property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Path { get; set; } +#nullable restore +#else + public string Path { get; set; } +#endif + /// The signedURL property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? SignedURL { get; set; } +#nullable restore +#else + public string SignedURL { get; set; } +#endif + /// + /// Instantiates a new and sets the default values. + /// + public SignedUrlResult() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.SignedUrlResult CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.SignedUrlResult(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "error", n => { Error = n.GetStringValue(); } }, + { "path", n => { Path = n.GetStringValue(); } }, + { "signedURL", n => { SignedURL = n.GetStringValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("error", Error); + writer.WriteStringValue("path", Path); + writer.WriteStringValue("signedURL", SignedURL); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/SortBy.cs b/kiota-spike/generated/Storage/Models/SortBy.cs new file mode 100644 index 00000000..36941053 --- /dev/null +++ b/kiota-spike/generated/Storage/Models/SortBy.cs @@ -0,0 +1,75 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class SortBy : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// The column property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Column { get; set; } +#nullable restore +#else + public string Column { get; set; } +#endif + /// The order property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Order { get; set; } +#nullable restore +#else + public string Order { get; set; } +#endif + /// + /// Instantiates a new and sets the default values. + /// + public SortBy() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.SortBy CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.SortBy(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "column", n => { Column = n.GetStringValue(); } }, + { "order", n => { Order = n.GetStringValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("column", Column); + writer.WriteStringValue("order", Order); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/StorageErrorResponseContent.cs b/kiota-spike/generated/Storage/Models/StorageErrorResponseContent.cs new file mode 100644 index 00000000..ad7bdf87 --- /dev/null +++ b/kiota-spike/generated/Storage/Models/StorageErrorResponseContent.cs @@ -0,0 +1,88 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class StorageErrorResponseContent : ApiException, IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// The error property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Error { get; set; } +#nullable restore +#else + public string Error { get; set; } +#endif + /// The primary error message. + public override string Message { get => MessageEscaped ?? string.Empty; } + /// The message property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? MessageEscaped { get; set; } +#nullable restore +#else + public string MessageEscaped { get; set; } +#endif + /// The statusCode property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? StatusCode { get; set; } +#nullable restore +#else + public string StatusCode { get; set; } +#endif + /// + /// Instantiates a new and sets the default values. + /// + public StorageErrorResponseContent() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "error", n => { Error = n.GetStringValue(); } }, + { "message", n => { MessageEscaped = n.GetStringValue(); } }, + { "statusCode", n => { StatusCode = n.GetStringValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("error", Error); + writer.WriteStringValue("message", MessageEscaped); + writer.WriteStringValue("statusCode", StatusCode); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/UpdateBucketRequestContent.cs b/kiota-spike/generated/Storage/Models/UpdateBucketRequestContent.cs new file mode 100644 index 00000000..edd27c88 --- /dev/null +++ b/kiota-spike/generated/Storage/Models/UpdateBucketRequestContent.cs @@ -0,0 +1,73 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class UpdateBucketRequestContent : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// Common string list shape reused across services. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public List? AllowedMimeTypes { get; set; } +#nullable restore +#else + public List AllowedMimeTypes { get; set; } +#endif + /// The file_size_limit property + public double? FileSizeLimit { get; set; } + /// The public property + public bool? Public { get; set; } + /// + /// Instantiates a new and sets the default values. + /// + public UpdateBucketRequestContent() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.UpdateBucketRequestContent CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.UpdateBucketRequestContent(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "allowed_mime_types", n => { AllowedMimeTypes = n.GetCollectionOfPrimitiveValues()?.AsList(); } }, + { "file_size_limit", n => { FileSizeLimit = n.GetDoubleValue(); } }, + { "public", n => { Public = n.GetBoolValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteCollectionOfPrimitiveValues("allowed_mime_types", AllowedMimeTypes); + writer.WriteDoubleValue("file_size_limit", FileSizeLimit); + writer.WriteBoolValue("public", Public); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/UpdateObjectResponseContent.cs b/kiota-spike/generated/Storage/Models/UpdateObjectResponseContent.cs new file mode 100644 index 00000000..c2a535fe --- /dev/null +++ b/kiota-spike/generated/Storage/Models/UpdateObjectResponseContent.cs @@ -0,0 +1,75 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class UpdateObjectResponseContent : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// The Id property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Id { get; set; } +#nullable restore +#else + public string Id { get; set; } +#endif + /// The Key property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Key { get; set; } +#nullable restore +#else + public string Key { get; set; } +#endif + /// + /// Instantiates a new and sets the default values. + /// + public UpdateObjectResponseContent() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.UpdateObjectResponseContent CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.UpdateObjectResponseContent(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "Id", n => { Id = n.GetStringValue(); } }, + { "Key", n => { Key = n.GetStringValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("Id", Id); + writer.WriteStringValue("Key", Key); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Models/UploadObjectResponseContent.cs b/kiota-spike/generated/Storage/Models/UploadObjectResponseContent.cs new file mode 100644 index 00000000..83a88e77 --- /dev/null +++ b/kiota-spike/generated/Storage/Models/UploadObjectResponseContent.cs @@ -0,0 +1,75 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class UploadObjectResponseContent : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// The Id property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Id { get; set; } +#nullable restore +#else + public string Id { get; set; } +#endif + /// The Key property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Key { get; set; } +#nullable restore +#else + public string Key { get; set; } +#endif + /// + /// Instantiates a new and sets the default values. + /// + public UploadObjectResponseContent() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.Models.UploadObjectResponseContent CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.Models.UploadObjectResponseContent(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "Id", n => { Id = n.GetStringValue(); } }, + { "Key", n => { Key = n.GetStringValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("Id", Id); + writer.WriteStringValue("Key", Key); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/ObjectNamespace/Copy/CopyRequestBuilder.cs b/kiota-spike/generated/Storage/ObjectNamespace/Copy/CopyRequestBuilder.cs new file mode 100644 index 00000000..18cbfa8f --- /dev/null +++ b/kiota-spike/generated/Storage/ObjectNamespace/Copy/CopyRequestBuilder.cs @@ -0,0 +1,96 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.Models; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Supabase.Storage.Kiota.ObjectNamespace.Copy +{ + /// + /// Builds and executes requests for operations under \object\copy + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class CopyRequestBuilder : BaseRequestBuilder + { + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public CopyRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/copy", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public CopyRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/copy", rawUrl) + { + } + /// A + /// The request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PostAsync(global::Supabase.Storage.Kiota.Models.CopyObjectRequestContent body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PostAsync(global::Supabase.Storage.Kiota.Models.CopyObjectRequestContent body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPostRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendAsync(requestInfo, global::Supabase.Storage.Kiota.Models.CopyObjectResponseContent.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// The request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPostRequestInformation(global::Supabase.Storage.Kiota.Models.CopyObjectRequestContent body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPostRequestInformation(global::Supabase.Storage.Kiota.Models.CopyObjectRequestContent body, Action> requestConfiguration = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.POST, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + requestInfo.SetContentFromParsable(RequestAdapter, "application/json", body); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Supabase.Storage.Kiota.ObjectNamespace.Copy.CopyRequestBuilder WithUrl(string rawUrl) + { + return new global::Supabase.Storage.Kiota.ObjectNamespace.Copy.CopyRequestBuilder(rawUrl, RequestAdapter); + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class CopyRequestBuilderPostRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/ObjectNamespace/Info/InfoRequestBuilder.cs b/kiota-spike/generated/Storage/ObjectNamespace/Info/InfoRequestBuilder.cs new file mode 100644 index 00000000..6a005952 --- /dev/null +++ b/kiota-spike/generated/Storage/ObjectNamespace/Info/InfoRequestBuilder.cs @@ -0,0 +1,48 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.ObjectNamespace.Info.Item; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System; +namespace Supabase.Storage.Kiota.ObjectNamespace.Info +{ + /// + /// Builds and executes requests for operations under \object\info + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class InfoRequestBuilder : BaseRequestBuilder + { + /// Gets an item from the Supabase.Storage.Kiota.object.info.item collection + /// Unique identifier of the item + /// A + public global::Supabase.Storage.Kiota.ObjectNamespace.Info.Item.WithBucketItemRequestBuilder this[string position] + { + get + { + var urlTplParams = new Dictionary(PathParameters); + urlTplParams.Add("bucketId", position); + return new global::Supabase.Storage.Kiota.ObjectNamespace.Info.Item.WithBucketItemRequestBuilder(urlTplParams, RequestAdapter); + } + } + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public InfoRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/info", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public InfoRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/info", rawUrl) + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/ObjectNamespace/Info/Item/Item/WithWildcardPathItemRequestBuilder.cs b/kiota-spike/generated/Storage/ObjectNamespace/Info/Item/Item/WithWildcardPathItemRequestBuilder.cs new file mode 100644 index 00000000..3592a8a4 --- /dev/null +++ b/kiota-spike/generated/Storage/ObjectNamespace/Info/Item/Item/WithWildcardPathItemRequestBuilder.cs @@ -0,0 +1,91 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.Models; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Supabase.Storage.Kiota.ObjectNamespace.Info.Item.Item +{ + /// + /// Builds and executes requests for operations under \object\info\{bucketId}\{wildcardPath} + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithWildcardPathItemRequestBuilder : BaseRequestBuilder + { + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public WithWildcardPathItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/info/{bucketId}/{wildcardPath}", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public WithWildcardPathItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/info/{bucketId}/{wildcardPath}", rawUrl) + { + } + /// A + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task GetAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + var requestInfo = ToGetRequestInformation(requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendAsync(requestInfo, global::Supabase.Storage.Kiota.Models.GetObjectInfoResponseContent.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToGetRequestInformation(Action> requestConfiguration = default) + { +#endif + var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Supabase.Storage.Kiota.ObjectNamespace.Info.Item.Item.WithWildcardPathItemRequestBuilder WithUrl(string rawUrl) + { + return new global::Supabase.Storage.Kiota.ObjectNamespace.Info.Item.Item.WithWildcardPathItemRequestBuilder(rawUrl, RequestAdapter); + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithWildcardPathItemRequestBuilderGetRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/ObjectNamespace/Info/Item/WithBucketItemRequestBuilder.cs b/kiota-spike/generated/Storage/ObjectNamespace/Info/Item/WithBucketItemRequestBuilder.cs new file mode 100644 index 00000000..2da263b6 --- /dev/null +++ b/kiota-spike/generated/Storage/ObjectNamespace/Info/Item/WithBucketItemRequestBuilder.cs @@ -0,0 +1,48 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.ObjectNamespace.Info.Item.Item; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System; +namespace Supabase.Storage.Kiota.ObjectNamespace.Info.Item +{ + /// + /// Builds and executes requests for operations under \object\info\{bucketId} + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithBucketItemRequestBuilder : BaseRequestBuilder + { + /// Gets an item from the Supabase.Storage.Kiota.object.info.item.item collection + /// Unique identifier of the item + /// A + public global::Supabase.Storage.Kiota.ObjectNamespace.Info.Item.Item.WithWildcardPathItemRequestBuilder this[string position] + { + get + { + var urlTplParams = new Dictionary(PathParameters); + urlTplParams.Add("wildcardPath", position); + return new global::Supabase.Storage.Kiota.ObjectNamespace.Info.Item.Item.WithWildcardPathItemRequestBuilder(urlTplParams, RequestAdapter); + } + } + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public WithBucketItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/info/{bucketId}", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public WithBucketItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/info/{bucketId}", rawUrl) + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/ObjectNamespace/Item/Item/WithWildcardPathItemRequestBuilder.cs b/kiota-spike/generated/Storage/ObjectNamespace/Item/Item/WithWildcardPathItemRequestBuilder.cs new file mode 100644 index 00000000..b8c16d8e --- /dev/null +++ b/kiota-spike/generated/Storage/ObjectNamespace/Item/Item/WithWildcardPathItemRequestBuilder.cs @@ -0,0 +1,201 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.Models; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Supabase.Storage.Kiota.ObjectNamespace.Item.Item +{ + /// + /// Builds and executes requests for operations under \object\{bucketId}\{wildcardPath} + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithWildcardPathItemRequestBuilder : BaseRequestBuilder + { + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public WithWildcardPathItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/{bucketId}/{wildcardPath}", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public WithWildcardPathItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/{bucketId}/{wildcardPath}", rawUrl) + { + } + /// A + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task HeadAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task HeadAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + var requestInfo = ToHeadRequestInformation(requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// + /// Upload a new object. Body is multipart/form-data with a required file part.Smithy has no native multipart/form-data support; the @httpMultipartForm traitdocuments intent and patch-openapi.py injects the correct requestBody schema. + /// + /// A + /// The request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PostAsync(MultipartBody body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PostAsync(MultipartBody body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPostRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendAsync(requestInfo, global::Supabase.Storage.Kiota.Models.UploadObjectResponseContent.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// + /// Replace an existing object. Body is multipart/form-data (see UploadObject). + /// + /// A + /// The request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PutAsync(MultipartBody body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PutAsync(MultipartBody body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPutRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendAsync(requestInfo, global::Supabase.Storage.Kiota.Models.UpdateObjectResponseContent.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToHeadRequestInformation(Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToHeadRequestInformation(Action> requestConfiguration = default) + { +#endif + var requestInfo = new RequestInformation(Method.HEAD, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + return requestInfo; + } + /// + /// Upload a new object. Body is multipart/form-data with a required file part.Smithy has no native multipart/form-data support; the @httpMultipartForm traitdocuments intent and patch-openapi.py injects the correct requestBody schema. + /// + /// A + /// The request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPostRequestInformation(MultipartBody body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPostRequestInformation(MultipartBody body, Action> requestConfiguration = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.POST, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + requestInfo.SetContentFromParsable(RequestAdapter, "multipart/form-data", body); + return requestInfo; + } + /// + /// Replace an existing object. Body is multipart/form-data (see UploadObject). + /// + /// A + /// The request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPutRequestInformation(MultipartBody body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPutRequestInformation(MultipartBody body, Action> requestConfiguration = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.PUT, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + requestInfo.SetContentFromParsable(RequestAdapter, "multipart/form-data", body); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Supabase.Storage.Kiota.ObjectNamespace.Item.Item.WithWildcardPathItemRequestBuilder WithUrl(string rawUrl) + { + return new global::Supabase.Storage.Kiota.ObjectNamespace.Item.Item.WithWildcardPathItemRequestBuilder(rawUrl, RequestAdapter); + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithWildcardPathItemRequestBuilderHeadRequestConfiguration : RequestConfiguration + { + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithWildcardPathItemRequestBuilderPostRequestConfiguration : RequestConfiguration + { + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithWildcardPathItemRequestBuilderPutRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/ObjectNamespace/Item/Item/WithWildcardPathPostRequestBody.cs b/kiota-spike/generated/Storage/ObjectNamespace/Item/Item/WithWildcardPathPostRequestBody.cs new file mode 100644 index 00000000..2331a540 --- /dev/null +++ b/kiota-spike/generated/Storage/ObjectNamespace/Item/Item/WithWildcardPathPostRequestBody.cs @@ -0,0 +1,55 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.ObjectNamespace.Item.Item +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class WithWildcardPathPostRequestBody : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// + /// Instantiates a new and sets the default values. + /// + public WithWildcardPathPostRequestBody() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.ObjectNamespace.Item.Item.WithWildcardPathPostRequestBody CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.ObjectNamespace.Item.Item.WithWildcardPathPostRequestBody(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/ObjectNamespace/Item/Item/WithWildcardPathPutRequestBody.cs b/kiota-spike/generated/Storage/ObjectNamespace/Item/Item/WithWildcardPathPutRequestBody.cs new file mode 100644 index 00000000..c3ad3f33 --- /dev/null +++ b/kiota-spike/generated/Storage/ObjectNamespace/Item/Item/WithWildcardPathPutRequestBody.cs @@ -0,0 +1,55 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace Supabase.Storage.Kiota.ObjectNamespace.Item.Item +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class WithWildcardPathPutRequestBody : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// + /// Instantiates a new and sets the default values. + /// + public WithWildcardPathPutRequestBody() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::Supabase.Storage.Kiota.ObjectNamespace.Item.Item.WithWildcardPathPutRequestBody CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::Supabase.Storage.Kiota.ObjectNamespace.Item.Item.WithWildcardPathPutRequestBody(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/ObjectNamespace/Item/WithBucketItemRequestBuilder.cs b/kiota-spike/generated/Storage/ObjectNamespace/Item/WithBucketItemRequestBuilder.cs new file mode 100644 index 00000000..13a4e75e --- /dev/null +++ b/kiota-spike/generated/Storage/ObjectNamespace/Item/WithBucketItemRequestBuilder.cs @@ -0,0 +1,110 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.Models; +using Supabase.Storage.Kiota.ObjectNamespace.Item.Item; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Supabase.Storage.Kiota.ObjectNamespace.Item +{ + /// + /// Builds and executes requests for operations under \object\{bucketId} + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithBucketItemRequestBuilder : BaseRequestBuilder + { + /// Gets an item from the Supabase.Storage.Kiota.object.item.item collection + /// Unique identifier of the item + /// A + public global::Supabase.Storage.Kiota.ObjectNamespace.Item.Item.WithWildcardPathItemRequestBuilder this[string position] + { + get + { + var urlTplParams = new Dictionary(PathParameters); + urlTplParams.Add("wildcardPath", position); + return new global::Supabase.Storage.Kiota.ObjectNamespace.Item.Item.WithWildcardPathItemRequestBuilder(urlTplParams, RequestAdapter); + } + } + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public WithBucketItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/{bucketId}", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public WithBucketItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/{bucketId}", rawUrl) + { + } + /// A List<global::Supabase.Storage.Kiota.Models.FileObject> + /// The request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task?> DeleteAsync(global::Supabase.Storage.Kiota.Models.DeleteObjectsRequestContent body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task> DeleteAsync(global::Supabase.Storage.Kiota.Models.DeleteObjectsRequestContent body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToDeleteRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + var collectionResult = await RequestAdapter.SendCollectionAsync(requestInfo, global::Supabase.Storage.Kiota.Models.FileObject.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false); + return collectionResult?.AsList(); + } + /// A + /// The request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToDeleteRequestInformation(global::Supabase.Storage.Kiota.Models.DeleteObjectsRequestContent body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToDeleteRequestInformation(global::Supabase.Storage.Kiota.Models.DeleteObjectsRequestContent body, Action> requestConfiguration = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.DELETE, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + requestInfo.SetContentFromParsable(RequestAdapter, "application/json", body); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Supabase.Storage.Kiota.ObjectNamespace.Item.WithBucketItemRequestBuilder WithUrl(string rawUrl) + { + return new global::Supabase.Storage.Kiota.ObjectNamespace.Item.WithBucketItemRequestBuilder(rawUrl, RequestAdapter); + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithBucketItemRequestBuilderDeleteRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/ObjectNamespace/List/Item/WithBucketItemRequestBuilder.cs b/kiota-spike/generated/Storage/ObjectNamespace/List/Item/WithBucketItemRequestBuilder.cs new file mode 100644 index 00000000..8e5653f2 --- /dev/null +++ b/kiota-spike/generated/Storage/ObjectNamespace/List/Item/WithBucketItemRequestBuilder.cs @@ -0,0 +1,97 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.Models; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Supabase.Storage.Kiota.ObjectNamespace.List.Item +{ + /// + /// Builds and executes requests for operations under \object\list\{bucketId} + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithBucketItemRequestBuilder : BaseRequestBuilder + { + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public WithBucketItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/list/{bucketId}", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public WithBucketItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/list/{bucketId}", rawUrl) + { + } + /// A List<global::Supabase.Storage.Kiota.Models.FileObject> + /// The request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task?> PostAsync(global::Supabase.Storage.Kiota.Models.ListObjectsRequestContent body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task> PostAsync(global::Supabase.Storage.Kiota.Models.ListObjectsRequestContent body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPostRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + var collectionResult = await RequestAdapter.SendCollectionAsync(requestInfo, global::Supabase.Storage.Kiota.Models.FileObject.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false); + return collectionResult?.AsList(); + } + /// A + /// The request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPostRequestInformation(global::Supabase.Storage.Kiota.Models.ListObjectsRequestContent body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPostRequestInformation(global::Supabase.Storage.Kiota.Models.ListObjectsRequestContent body, Action> requestConfiguration = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.POST, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + requestInfo.SetContentFromParsable(RequestAdapter, "application/json", body); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Supabase.Storage.Kiota.ObjectNamespace.List.Item.WithBucketItemRequestBuilder WithUrl(string rawUrl) + { + return new global::Supabase.Storage.Kiota.ObjectNamespace.List.Item.WithBucketItemRequestBuilder(rawUrl, RequestAdapter); + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithBucketItemRequestBuilderPostRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/ObjectNamespace/List/ListRequestBuilder.cs b/kiota-spike/generated/Storage/ObjectNamespace/List/ListRequestBuilder.cs new file mode 100644 index 00000000..8dd5b7de --- /dev/null +++ b/kiota-spike/generated/Storage/ObjectNamespace/List/ListRequestBuilder.cs @@ -0,0 +1,48 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.ObjectNamespace.List.Item; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System; +namespace Supabase.Storage.Kiota.ObjectNamespace.List +{ + /// + /// Builds and executes requests for operations under \object\list + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class ListRequestBuilder : BaseRequestBuilder + { + /// Gets an item from the Supabase.Storage.Kiota.object.list.item collection + /// Unique identifier of the item + /// A + public global::Supabase.Storage.Kiota.ObjectNamespace.List.Item.WithBucketItemRequestBuilder this[string position] + { + get + { + var urlTplParams = new Dictionary(PathParameters); + urlTplParams.Add("bucketId", position); + return new global::Supabase.Storage.Kiota.ObjectNamespace.List.Item.WithBucketItemRequestBuilder(urlTplParams, RequestAdapter); + } + } + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public ListRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/list", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public ListRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/list", rawUrl) + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/ObjectNamespace/Move/MoveRequestBuilder.cs b/kiota-spike/generated/Storage/ObjectNamespace/Move/MoveRequestBuilder.cs new file mode 100644 index 00000000..52cfc1e5 --- /dev/null +++ b/kiota-spike/generated/Storage/ObjectNamespace/Move/MoveRequestBuilder.cs @@ -0,0 +1,96 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.Models; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Supabase.Storage.Kiota.ObjectNamespace.Move +{ + /// + /// Builds and executes requests for operations under \object\move + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class MoveRequestBuilder : BaseRequestBuilder + { + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public MoveRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/move", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public MoveRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/move", rawUrl) + { + } + /// A + /// The request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PostAsync(global::Supabase.Storage.Kiota.Models.MoveObjectRequestContent body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PostAsync(global::Supabase.Storage.Kiota.Models.MoveObjectRequestContent body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPostRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// The request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPostRequestInformation(global::Supabase.Storage.Kiota.Models.MoveObjectRequestContent body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPostRequestInformation(global::Supabase.Storage.Kiota.Models.MoveObjectRequestContent body, Action> requestConfiguration = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.POST, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + requestInfo.SetContentFromParsable(RequestAdapter, "application/json", body); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Supabase.Storage.Kiota.ObjectNamespace.Move.MoveRequestBuilder WithUrl(string rawUrl) + { + return new global::Supabase.Storage.Kiota.ObjectNamespace.Move.MoveRequestBuilder(rawUrl, RequestAdapter); + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class MoveRequestBuilderPostRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/ObjectNamespace/ObjectRequestBuilder.cs b/kiota-spike/generated/Storage/ObjectNamespace/ObjectRequestBuilder.cs new file mode 100644 index 00000000..d49ca92e --- /dev/null +++ b/kiota-spike/generated/Storage/ObjectNamespace/ObjectRequestBuilder.cs @@ -0,0 +1,84 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.ObjectNamespace.Copy; +using Supabase.Storage.Kiota.ObjectNamespace.Info; +using Supabase.Storage.Kiota.ObjectNamespace.Item; +using Supabase.Storage.Kiota.ObjectNamespace.List; +using Supabase.Storage.Kiota.ObjectNamespace.Move; +using Supabase.Storage.Kiota.ObjectNamespace.Sign; +using Supabase.Storage.Kiota.ObjectNamespace.Upload; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System; +namespace Supabase.Storage.Kiota.ObjectNamespace +{ + /// + /// Builds and executes requests for operations under \object + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class ObjectRequestBuilder : BaseRequestBuilder + { + /// The copy property + public global::Supabase.Storage.Kiota.ObjectNamespace.Copy.CopyRequestBuilder Copy + { + get => new global::Supabase.Storage.Kiota.ObjectNamespace.Copy.CopyRequestBuilder(PathParameters, RequestAdapter); + } + /// The info property + public global::Supabase.Storage.Kiota.ObjectNamespace.Info.InfoRequestBuilder Info + { + get => new global::Supabase.Storage.Kiota.ObjectNamespace.Info.InfoRequestBuilder(PathParameters, RequestAdapter); + } + /// The list property + public global::Supabase.Storage.Kiota.ObjectNamespace.List.ListRequestBuilder List + { + get => new global::Supabase.Storage.Kiota.ObjectNamespace.List.ListRequestBuilder(PathParameters, RequestAdapter); + } + /// The move property + public global::Supabase.Storage.Kiota.ObjectNamespace.Move.MoveRequestBuilder Move + { + get => new global::Supabase.Storage.Kiota.ObjectNamespace.Move.MoveRequestBuilder(PathParameters, RequestAdapter); + } + /// The sign property + public global::Supabase.Storage.Kiota.ObjectNamespace.Sign.SignRequestBuilder Sign + { + get => new global::Supabase.Storage.Kiota.ObjectNamespace.Sign.SignRequestBuilder(PathParameters, RequestAdapter); + } + /// The upload property + public global::Supabase.Storage.Kiota.ObjectNamespace.Upload.UploadRequestBuilder Upload + { + get => new global::Supabase.Storage.Kiota.ObjectNamespace.Upload.UploadRequestBuilder(PathParameters, RequestAdapter); + } + /// Gets an item from the Supabase.Storage.Kiota.object.item collection + /// Unique identifier of the item + /// A + public global::Supabase.Storage.Kiota.ObjectNamespace.Item.WithBucketItemRequestBuilder this[string position] + { + get + { + var urlTplParams = new Dictionary(PathParameters); + urlTplParams.Add("bucketId", position); + return new global::Supabase.Storage.Kiota.ObjectNamespace.Item.WithBucketItemRequestBuilder(urlTplParams, RequestAdapter); + } + } + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public ObjectRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public ObjectRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object", rawUrl) + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/ObjectNamespace/Sign/Item/Item/WithWildcardPathItemRequestBuilder.cs b/kiota-spike/generated/Storage/ObjectNamespace/Sign/Item/Item/WithWildcardPathItemRequestBuilder.cs new file mode 100644 index 00000000..d0848e63 --- /dev/null +++ b/kiota-spike/generated/Storage/ObjectNamespace/Sign/Item/Item/WithWildcardPathItemRequestBuilder.cs @@ -0,0 +1,96 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.Models; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Supabase.Storage.Kiota.ObjectNamespace.Sign.Item.Item +{ + /// + /// Builds and executes requests for operations under \object\sign\{bucketId}\{wildcardPath} + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithWildcardPathItemRequestBuilder : BaseRequestBuilder + { + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public WithWildcardPathItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/sign/{bucketId}/{wildcardPath}", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public WithWildcardPathItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/sign/{bucketId}/{wildcardPath}", rawUrl) + { + } + /// A + /// The request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PostAsync(global::Supabase.Storage.Kiota.Models.CreateSignedUrlRequestContent body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PostAsync(global::Supabase.Storage.Kiota.Models.CreateSignedUrlRequestContent body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPostRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendAsync(requestInfo, global::Supabase.Storage.Kiota.Models.CreateSignedUrlResponseContent.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// The request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPostRequestInformation(global::Supabase.Storage.Kiota.Models.CreateSignedUrlRequestContent body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPostRequestInformation(global::Supabase.Storage.Kiota.Models.CreateSignedUrlRequestContent body, Action> requestConfiguration = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.POST, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + requestInfo.SetContentFromParsable(RequestAdapter, "application/json", body); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Supabase.Storage.Kiota.ObjectNamespace.Sign.Item.Item.WithWildcardPathItemRequestBuilder WithUrl(string rawUrl) + { + return new global::Supabase.Storage.Kiota.ObjectNamespace.Sign.Item.Item.WithWildcardPathItemRequestBuilder(rawUrl, RequestAdapter); + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithWildcardPathItemRequestBuilderPostRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/ObjectNamespace/Sign/Item/WithBucketItemRequestBuilder.cs b/kiota-spike/generated/Storage/ObjectNamespace/Sign/Item/WithBucketItemRequestBuilder.cs new file mode 100644 index 00000000..b214bb15 --- /dev/null +++ b/kiota-spike/generated/Storage/ObjectNamespace/Sign/Item/WithBucketItemRequestBuilder.cs @@ -0,0 +1,110 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.Models; +using Supabase.Storage.Kiota.ObjectNamespace.Sign.Item.Item; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Supabase.Storage.Kiota.ObjectNamespace.Sign.Item +{ + /// + /// Builds and executes requests for operations under \object\sign\{bucketId} + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithBucketItemRequestBuilder : BaseRequestBuilder + { + /// Gets an item from the Supabase.Storage.Kiota.object.sign.item.item collection + /// Unique identifier of the item + /// A + public global::Supabase.Storage.Kiota.ObjectNamespace.Sign.Item.Item.WithWildcardPathItemRequestBuilder this[string position] + { + get + { + var urlTplParams = new Dictionary(PathParameters); + urlTplParams.Add("wildcardPath", position); + return new global::Supabase.Storage.Kiota.ObjectNamespace.Sign.Item.Item.WithWildcardPathItemRequestBuilder(urlTplParams, RequestAdapter); + } + } + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public WithBucketItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/sign/{bucketId}", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public WithBucketItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/sign/{bucketId}", rawUrl) + { + } + /// A List<global::Supabase.Storage.Kiota.Models.SignedUrlResult> + /// The request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task?> PostAsync(global::Supabase.Storage.Kiota.Models.CreateSignedUrlsRequestContent body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task> PostAsync(global::Supabase.Storage.Kiota.Models.CreateSignedUrlsRequestContent body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPostRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + var collectionResult = await RequestAdapter.SendCollectionAsync(requestInfo, global::Supabase.Storage.Kiota.Models.SignedUrlResult.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false); + return collectionResult?.AsList(); + } + /// A + /// The request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPostRequestInformation(global::Supabase.Storage.Kiota.Models.CreateSignedUrlsRequestContent body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPostRequestInformation(global::Supabase.Storage.Kiota.Models.CreateSignedUrlsRequestContent body, Action> requestConfiguration = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.POST, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + requestInfo.SetContentFromParsable(RequestAdapter, "application/json", body); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Supabase.Storage.Kiota.ObjectNamespace.Sign.Item.WithBucketItemRequestBuilder WithUrl(string rawUrl) + { + return new global::Supabase.Storage.Kiota.ObjectNamespace.Sign.Item.WithBucketItemRequestBuilder(rawUrl, RequestAdapter); + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithBucketItemRequestBuilderPostRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/ObjectNamespace/Sign/SignRequestBuilder.cs b/kiota-spike/generated/Storage/ObjectNamespace/Sign/SignRequestBuilder.cs new file mode 100644 index 00000000..e774fc45 --- /dev/null +++ b/kiota-spike/generated/Storage/ObjectNamespace/Sign/SignRequestBuilder.cs @@ -0,0 +1,48 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.ObjectNamespace.Sign.Item; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System; +namespace Supabase.Storage.Kiota.ObjectNamespace.Sign +{ + /// + /// Builds and executes requests for operations under \object\sign + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class SignRequestBuilder : BaseRequestBuilder + { + /// Gets an item from the Supabase.Storage.Kiota.object.sign.item collection + /// Unique identifier of the item + /// A + public global::Supabase.Storage.Kiota.ObjectNamespace.Sign.Item.WithBucketItemRequestBuilder this[string position] + { + get + { + var urlTplParams = new Dictionary(PathParameters); + urlTplParams.Add("bucketId", position); + return new global::Supabase.Storage.Kiota.ObjectNamespace.Sign.Item.WithBucketItemRequestBuilder(urlTplParams, RequestAdapter); + } + } + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public SignRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/sign", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public SignRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/sign", rawUrl) + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/ObjectNamespace/Upload/Sign/Item/Item/WithWildcardPathItemRequestBuilder.cs b/kiota-spike/generated/Storage/ObjectNamespace/Upload/Sign/Item/Item/WithWildcardPathItemRequestBuilder.cs new file mode 100644 index 00000000..61e10879 --- /dev/null +++ b/kiota-spike/generated/Storage/ObjectNamespace/Upload/Sign/Item/Item/WithWildcardPathItemRequestBuilder.cs @@ -0,0 +1,91 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.Models; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Supabase.Storage.Kiota.ObjectNamespace.Upload.Sign.Item.Item +{ + /// + /// Builds and executes requests for operations under \object\upload\sign\{bucketId}\{wildcardPath} + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithWildcardPathItemRequestBuilder : BaseRequestBuilder + { + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public WithWildcardPathItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/upload/sign/{bucketId}/{wildcardPath}", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public WithWildcardPathItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/upload/sign/{bucketId}/{wildcardPath}", rawUrl) + { + } + /// A + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PostAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PostAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + var requestInfo = ToPostRequestInformation(requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendAsync(requestInfo, global::Supabase.Storage.Kiota.Models.CreateSignedUploadUrlResponseContent.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPostRequestInformation(Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPostRequestInformation(Action> requestConfiguration = default) + { +#endif + var requestInfo = new RequestInformation(Method.POST, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Supabase.Storage.Kiota.ObjectNamespace.Upload.Sign.Item.Item.WithWildcardPathItemRequestBuilder WithUrl(string rawUrl) + { + return new global::Supabase.Storage.Kiota.ObjectNamespace.Upload.Sign.Item.Item.WithWildcardPathItemRequestBuilder(rawUrl, RequestAdapter); + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithWildcardPathItemRequestBuilderPostRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/ObjectNamespace/Upload/Sign/Item/WithBucketItemRequestBuilder.cs b/kiota-spike/generated/Storage/ObjectNamespace/Upload/Sign/Item/WithBucketItemRequestBuilder.cs new file mode 100644 index 00000000..47443815 --- /dev/null +++ b/kiota-spike/generated/Storage/ObjectNamespace/Upload/Sign/Item/WithBucketItemRequestBuilder.cs @@ -0,0 +1,48 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.ObjectNamespace.Upload.Sign.Item.Item; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System; +namespace Supabase.Storage.Kiota.ObjectNamespace.Upload.Sign.Item +{ + /// + /// Builds and executes requests for operations under \object\upload\sign\{bucketId} + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithBucketItemRequestBuilder : BaseRequestBuilder + { + /// Gets an item from the Supabase.Storage.Kiota.object.upload.sign.item.item collection + /// Unique identifier of the item + /// A + public global::Supabase.Storage.Kiota.ObjectNamespace.Upload.Sign.Item.Item.WithWildcardPathItemRequestBuilder this[string position] + { + get + { + var urlTplParams = new Dictionary(PathParameters); + urlTplParams.Add("wildcardPath", position); + return new global::Supabase.Storage.Kiota.ObjectNamespace.Upload.Sign.Item.Item.WithWildcardPathItemRequestBuilder(urlTplParams, RequestAdapter); + } + } + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public WithBucketItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/upload/sign/{bucketId}", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public WithBucketItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/upload/sign/{bucketId}", rawUrl) + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/ObjectNamespace/Upload/Sign/SignRequestBuilder.cs b/kiota-spike/generated/Storage/ObjectNamespace/Upload/Sign/SignRequestBuilder.cs new file mode 100644 index 00000000..da183f98 --- /dev/null +++ b/kiota-spike/generated/Storage/ObjectNamespace/Upload/Sign/SignRequestBuilder.cs @@ -0,0 +1,48 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.ObjectNamespace.Upload.Sign.Item; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System; +namespace Supabase.Storage.Kiota.ObjectNamespace.Upload.Sign +{ + /// + /// Builds and executes requests for operations under \object\upload\sign + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class SignRequestBuilder : BaseRequestBuilder + { + /// Gets an item from the Supabase.Storage.Kiota.object.upload.sign.item collection + /// Unique identifier of the item + /// A + public global::Supabase.Storage.Kiota.ObjectNamespace.Upload.Sign.Item.WithBucketItemRequestBuilder this[string position] + { + get + { + var urlTplParams = new Dictionary(PathParameters); + urlTplParams.Add("bucketId", position); + return new global::Supabase.Storage.Kiota.ObjectNamespace.Upload.Sign.Item.WithBucketItemRequestBuilder(urlTplParams, RequestAdapter); + } + } + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public SignRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/upload/sign", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public SignRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/upload/sign", rawUrl) + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/ObjectNamespace/Upload/UploadRequestBuilder.cs b/kiota-spike/generated/Storage/ObjectNamespace/Upload/UploadRequestBuilder.cs new file mode 100644 index 00000000..5d3ac7b5 --- /dev/null +++ b/kiota-spike/generated/Storage/ObjectNamespace/Upload/UploadRequestBuilder.cs @@ -0,0 +1,41 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.ObjectNamespace.Upload.Sign; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System; +namespace Supabase.Storage.Kiota.ObjectNamespace.Upload +{ + /// + /// Builds and executes requests for operations under \object\upload + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class UploadRequestBuilder : BaseRequestBuilder + { + /// The sign property + public global::Supabase.Storage.Kiota.ObjectNamespace.Upload.Sign.SignRequestBuilder Sign + { + get => new global::Supabase.Storage.Kiota.ObjectNamespace.Upload.Sign.SignRequestBuilder(PathParameters, RequestAdapter); + } + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public UploadRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/upload", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public UploadRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/object/upload", rawUrl) + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/StorageApiClient.cs b/kiota-spike/generated/Storage/StorageApiClient.cs new file mode 100644 index 00000000..6f4bc8ce --- /dev/null +++ b/kiota-spike/generated/Storage/StorageApiClient.cs @@ -0,0 +1,55 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions; +using Microsoft.Kiota.Serialization.Form; +using Microsoft.Kiota.Serialization.Json; +using Microsoft.Kiota.Serialization.Multipart; +using Microsoft.Kiota.Serialization.Text; +using Supabase.Storage.Kiota.Bucket; +using Supabase.Storage.Kiota.ObjectNamespace; +using Supabase.Storage.Kiota.Upload; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System; +namespace Supabase.Storage.Kiota +{ + /// + /// The main entry point of the SDK, exposes the configuration and the fluent API. + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class StorageApiClient : BaseRequestBuilder + { + /// The bucket property + public global::Supabase.Storage.Kiota.Bucket.BucketRequestBuilder Bucket + { + get => new global::Supabase.Storage.Kiota.Bucket.BucketRequestBuilder(PathParameters, RequestAdapter); + } + /// The object property + public global::Supabase.Storage.Kiota.ObjectNamespace.ObjectRequestBuilder Object + { + get => new global::Supabase.Storage.Kiota.ObjectNamespace.ObjectRequestBuilder(PathParameters, RequestAdapter); + } + /// The upload property + public global::Supabase.Storage.Kiota.Upload.UploadRequestBuilder Upload + { + get => new global::Supabase.Storage.Kiota.Upload.UploadRequestBuilder(PathParameters, RequestAdapter); + } + /// + /// Instantiates a new and sets the default values. + /// + /// The request adapter to use to execute the requests. + public StorageApiClient(IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}", new Dictionary()) + { + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultDeserializer(); + ApiClientBuilder.RegisterDefaultDeserializer(); + ApiClientBuilder.RegisterDefaultDeserializer(); + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Upload/Resumable/Item/WithUploadItemRequestBuilder.cs b/kiota-spike/generated/Storage/Upload/Resumable/Item/WithUploadItemRequestBuilder.cs new file mode 100644 index 00000000..60d5d392 --- /dev/null +++ b/kiota-spike/generated/Storage/Upload/Resumable/Item/WithUploadItemRequestBuilder.cs @@ -0,0 +1,151 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.Models; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Supabase.Storage.Kiota.Upload.Resumable.Item +{ + /// + /// Builds and executes requests for operations under \upload\resumable\{uploadId} + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithUploadItemRequestBuilder : BaseRequestBuilder + { + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public WithUploadItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/upload/resumable/{uploadId}", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public WithUploadItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/upload/resumable/{uploadId}", rawUrl) + { + } + /// + /// Step 3: Query the server-side offset of a TUS session (used when resuming). + /// + /// A + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task HeadAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task HeadAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + var requestInfo = ToHeadRequestInformation(requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendPrimitiveAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// + /// Step 2: Upload a chunk of data to an existing TUS session.Repeat with increasing Upload-Offset until all bytes are sent. + /// + /// Binary request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PatchAsync(Stream body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PatchAsync(Stream body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPatchRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + await RequestAdapter.SendNoContentAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// + /// Step 3: Query the server-side offset of a TUS session (used when resuming). + /// + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToHeadRequestInformation(Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToHeadRequestInformation(Action> requestConfiguration = default) + { +#endif + var requestInfo = new RequestInformation(Method.HEAD, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + return requestInfo; + } + /// + /// Step 2: Upload a chunk of data to an existing TUS session.Repeat with increasing Upload-Offset until all bytes are sent. + /// + /// A + /// Binary request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPatchRequestInformation(Stream body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPatchRequestInformation(Stream body, Action> requestConfiguration = default) + { +#endif + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.PATCH, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + requestInfo.SetStreamContent(body, "application/octet-stream"); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Supabase.Storage.Kiota.Upload.Resumable.Item.WithUploadItemRequestBuilder WithUrl(string rawUrl) + { + return new global::Supabase.Storage.Kiota.Upload.Resumable.Item.WithUploadItemRequestBuilder(rawUrl, RequestAdapter); + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithUploadItemRequestBuilderHeadRequestConfiguration : RequestConfiguration + { + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class WithUploadItemRequestBuilderPatchRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Upload/Resumable/ResumableRequestBuilder.cs b/kiota-spike/generated/Storage/Upload/Resumable/ResumableRequestBuilder.cs new file mode 100644 index 00000000..9d0ca3e7 --- /dev/null +++ b/kiota-spike/generated/Storage/Upload/Resumable/ResumableRequestBuilder.cs @@ -0,0 +1,109 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.Models; +using Supabase.Storage.Kiota.Upload.Resumable.Item; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace Supabase.Storage.Kiota.Upload.Resumable +{ + /// + /// Builds and executes requests for operations under \upload\resumable + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class ResumableRequestBuilder : BaseRequestBuilder + { + /// Gets an item from the Supabase.Storage.Kiota.upload.resumable.item collection + /// Unique identifier of the item + /// A + public global::Supabase.Storage.Kiota.Upload.Resumable.Item.WithUploadItemRequestBuilder this[string position] + { + get + { + var urlTplParams = new Dictionary(PathParameters); + urlTplParams.Add("uploadId", position); + return new global::Supabase.Storage.Kiota.Upload.Resumable.Item.WithUploadItemRequestBuilder(urlTplParams, RequestAdapter); + } + } + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public ResumableRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/upload/resumable", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public ResumableRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/upload/resumable", rawUrl) + { + } + /// + /// Step 1: Create a new TUS upload session.The server responds with a Location header containing the upload URL. + /// + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PostAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PostAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + var requestInfo = ToPostRequestInformation(requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::Supabase.Storage.Kiota.Models.StorageErrorResponseContent.CreateFromDiscriminatorValue }, + }; + await RequestAdapter.SendNoContentAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + /// + /// Step 1: Create a new TUS upload session.The server responds with a Location header containing the upload URL. + /// + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPostRequestInformation(Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPostRequestInformation(Action> requestConfiguration = default) + { +#endif + var requestInfo = new RequestInformation(Method.POST, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::Supabase.Storage.Kiota.Upload.Resumable.ResumableRequestBuilder WithUrl(string rawUrl) + { + return new global::Supabase.Storage.Kiota.Upload.Resumable.ResumableRequestBuilder(rawUrl, RequestAdapter); + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class ResumableRequestBuilderPostRequestConfiguration : RequestConfiguration + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/Upload/UploadRequestBuilder.cs b/kiota-spike/generated/Storage/Upload/UploadRequestBuilder.cs new file mode 100644 index 00000000..76081346 --- /dev/null +++ b/kiota-spike/generated/Storage/Upload/UploadRequestBuilder.cs @@ -0,0 +1,41 @@ +// +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions; +using Supabase.Storage.Kiota.Upload.Resumable; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System; +namespace Supabase.Storage.Kiota.Upload +{ + /// + /// Builds and executes requests for operations under \upload + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class UploadRequestBuilder : BaseRequestBuilder + { + /// The resumable property + public global::Supabase.Storage.Kiota.Upload.Resumable.ResumableRequestBuilder Resumable + { + get => new global::Supabase.Storage.Kiota.Upload.Resumable.ResumableRequestBuilder(PathParameters, RequestAdapter); + } + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public UploadRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/upload", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public UploadRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/upload", rawUrl) + { + } + } +} +#pragma warning restore CS0618 diff --git a/kiota-spike/generated/Storage/kiota-lock.json b/kiota-spike/generated/Storage/kiota-lock.json new file mode 100644 index 00000000..8e73a320 --- /dev/null +++ b/kiota-spike/generated/Storage/kiota-lock.json @@ -0,0 +1,34 @@ +{ + "descriptionHash": "EF5CC21699DFEF72FEF59CAA8C4D3FFE9579F619B1F497D7792BF978CE7794661C4575E2845DD5CD6EA7E68FFD76BDC56AB8A22AE4BB4DB20D34841A5069A64E", + "descriptionLocation": "../StorageService.ready.json", + "lockFileVersion": "1.0.0", + "kiotaVersion": "1.32.4", + "clientClassName": "StorageApiClient", + "typeAccessModifier": "Public", + "clientNamespaceName": "Supabase.Storage.Kiota", + "language": "CSharp", + "usesBackingStore": false, + "excludeBackwardCompatible": false, + "includeAdditionalData": true, + "disableSSLValidation": false, + "serializers": [ + "Microsoft.Kiota.Serialization.Json.JsonSerializationWriterFactory", + "Microsoft.Kiota.Serialization.Text.TextSerializationWriterFactory", + "Microsoft.Kiota.Serialization.Form.FormSerializationWriterFactory", + "Microsoft.Kiota.Serialization.Multipart.MultipartSerializationWriterFactory" + ], + "deserializers": [ + "Microsoft.Kiota.Serialization.Json.JsonParseNodeFactory", + "Microsoft.Kiota.Serialization.Text.TextParseNodeFactory", + "Microsoft.Kiota.Serialization.Form.FormParseNodeFactory" + ], + "structuredMimeTypes": [ + "application/json", + "text/plain;q=0.9", + "application/x-www-form-urlencoded;q=0.2", + "multipart/form-data;q=0.1" + ], + "includePatterns": [], + "excludePatterns": [], + "disabledValidationRules": [] +} \ No newline at end of file diff --git a/kiota-spike/generated/StorageService.ready.json b/kiota-spike/generated/StorageService.ready.json new file mode 100644 index 00000000..49f2dec5 --- /dev/null +++ b/kiota-spike/generated/StorageService.ready.json @@ -0,0 +1,1365 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Supabase Storage API", + "version": "1.0" + }, + "paths": { + "/bucket": { + "get": { + "operationId": "ListBuckets", + "responses": { + "200": { + "description": "ListBuckets 200 response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Bucket" + } + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "post": { + "operationId": "CreateBucket", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateBucketRequestContent" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "CreateBucket 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/bucket/{id}": { + "delete": { + "operationId": "DeleteBucket", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "DeleteBucket 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "get": { + "operationId": "GetBucket", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "GetBucket 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetBucketResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "put": { + "operationId": "UpdateBucket", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateBucketRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "UpdateBucket 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/bucket/{id}/empty": { + "post": { + "operationId": "EmptyBucket", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "EmptyBucket 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/copy": { + "post": { + "operationId": "CopyObject", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CopyObjectRequestContent" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "CopyObject 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CopyObjectResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/info/{bucketId}/{wildcardPath}": { + "get": { + "operationId": "GetObjectInfo", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "GetObjectInfo 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetObjectInfoResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/list/{bucketId}": { + "post": { + "operationId": "ListObjects", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListObjectsRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "ListObjects 200 response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileObject" + } + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/move": { + "post": { + "operationId": "MoveObject", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MoveObjectRequestContent" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "MoveObject 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/sign/{bucketId}": { + "post": { + "operationId": "CreateSignedUrls", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSignedUrlsRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "CreateSignedUrls 200 response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SignedUrlResult" + } + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/sign/{bucketId}/{wildcardPath}": { + "post": { + "operationId": "CreateSignedUrl", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSignedUrlRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "CreateSignedUrl 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSignedUrlResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/upload/sign/{bucketId}/{wildcardPath}": { + "post": { + "operationId": "CreateSignedUploadUrl", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "x-upsert", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "CreateSignedUploadUrl 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSignedUploadUrlResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/{bucketId}": { + "delete": { + "operationId": "DeleteObjects", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteObjectsRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "DeleteObjects 200 response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileObject" + } + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/{bucketId}/{wildcardPath}": { + "head": { + "operationId": "HeadObject", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "HeadObject 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "post": { + "description": "Upload a new object. Body is multipart/form-data with a required file part.\nSmithy has no native multipart/form-data support; the @httpMultipartForm trait\ndocuments intent and patch-openapi.py injects the correct requestBody schema.", + "operationId": "UploadObject", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "x-upsert", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "UploadObject 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UploadObjectResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + }, + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "required": [ + "file" + ], + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "cacheControl": { + "type": "string" + }, + "metadata": { + "type": "object" + } + } + } + } + } + } + }, + "put": { + "description": "Replace an existing object. Body is multipart/form-data (see UploadObject).", + "operationId": "UpdateObject", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "UpdateObject 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateObjectResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + }, + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "required": [ + "file" + ], + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "cacheControl": { + "type": "string" + }, + "metadata": { + "type": "object" + } + } + } + } + } + } + } + }, + "/upload/resumable": { + "post": { + "description": "Step 1: Create a new TUS upload session.\nThe server responds with a Location header containing the upload URL.", + "operationId": "CreateTusUpload", + "parameters": [ + { + "name": "Tus-Resumable", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "Upload-Length", + "in": "header", + "description": "Total size of the file in bytes.", + "schema": { + "type": "number", + "description": "Total size of the file in bytes." + }, + "required": true + }, + { + "name": "Upload-Metadata", + "in": "header", + "description": "Base64-encoded TUS metadata (bucketName, objectName, contentType, cacheControl).", + "schema": { + "type": "string", + "description": "Base64-encoded TUS metadata (bucketName, objectName, contentType, cacheControl)." + }, + "required": true + }, + { + "name": "x-upsert", + "in": "header", + "description": "Set to \"true\" to overwrite an existing object at the same path.", + "schema": { + "type": "string", + "description": "Set to \"true\" to overwrite an existing object at the same path." + } + } + ], + "responses": { + "201": { + "description": "CreateTusUpload 201 response", + "headers": { + "Location": { + "description": "Full URL of the created upload session. Used in subsequent PATCH/HEAD requests.", + "schema": { + "type": "string", + "description": "Full URL of the created upload session. Used in subsequent PATCH/HEAD requests." + }, + "required": true + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/upload/resumable/{uploadId}": { + "head": { + "description": "Step 3: Query the server-side offset of a TUS session (used when resuming).", + "operationId": "GetUploadOffset", + "parameters": [ + { + "name": "uploadId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "Tus-Resumable", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "GetUploadOffset 200 response", + "headers": { + "Upload-Offset": { + "schema": { + "type": "number" + }, + "required": true + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "patch": { + "description": "Step 2: Upload a chunk of data to an existing TUS session.\nRepeat with increasing Upload-Offset until all bytes are sent.", + "operationId": "UploadChunk", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "uploadId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "Tus-Resumable", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "Upload-Offset", + "in": "header", + "description": "Byte offset at which this chunk begins.", + "schema": { + "type": "number", + "description": "Byte offset at which this chunk begins." + }, + "required": true + } + ], + "responses": { + "204": { + "description": "UploadChunk 204 response", + "headers": { + "Upload-Offset": { + "description": "New server-side offset after the chunk was accepted.", + "schema": { + "type": "number", + "description": "New server-side offset after the chunk was accepted." + }, + "required": true + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Bucket": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "public": { + "type": "boolean" + }, + "file_size_limit": { + "type": "number", + "nullable": true + }, + "allowed_mime_types": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "public" + ] + }, + "CopyObjectRequestContent": { + "type": "object", + "properties": { + "bucketId": { + "type": "string" + }, + "sourceKey": { + "type": "string" + }, + "destinationKey": { + "type": "string" + }, + "destinationBucket": { + "type": "string" + } + }, + "required": [ + "bucketId", + "destinationKey", + "sourceKey" + ] + }, + "CopyObjectResponseContent": { + "type": "object", + "properties": { + "Key": { + "type": "string" + } + }, + "required": [ + "Key" + ] + }, + "CreateBucketRequestContent": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "public": { + "type": "boolean" + }, + "file_size_limit": { + "type": "number", + "nullable": true + }, + "allowed_mime_types": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + } + }, + "required": [ + "id", + "name", + "public" + ] + }, + "CreateSignedUploadUrlResponseContent": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + }, + "required": [ + "url" + ] + }, + "CreateSignedUrlRequestContent": { + "type": "object", + "properties": { + "expiresIn": { + "type": "number" + } + }, + "required": [ + "expiresIn" + ] + }, + "CreateSignedUrlResponseContent": { + "type": "object", + "properties": { + "signedURL": { + "type": "string" + } + }, + "required": [ + "signedURL" + ] + }, + "CreateSignedUrlsRequestContent": { + "type": "object", + "properties": { + "expiresIn": { + "type": "number" + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + } + }, + "required": [ + "expiresIn", + "paths" + ] + }, + "DeleteObjectsRequestContent": { + "type": "object", + "properties": { + "prefixes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + } + }, + "required": [ + "prefixes" + ] + }, + "FileMetadata": { + "type": "object", + "properties": { + "eTag": { + "type": "string" + }, + "size": { + "type": "number", + "nullable": true + }, + "mimetype": { + "type": "string" + }, + "cacheControl": { + "type": "string" + }, + "lastModified": { + "type": "string" + }, + "contentLength": { + "type": "number", + "nullable": true + }, + "httpStatusCode": { + "type": "number", + "nullable": true + } + } + }, + "FileObject": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "id": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "last_accessed_at": { + "type": "string" + }, + "metadata": { + "$ref": "#/components/schemas/FileMetadata" + } + }, + "required": [ + "name" + ] + }, + "GetBucketResponseContent": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "public": { + "type": "boolean" + }, + "file_size_limit": { + "type": "number", + "nullable": true + }, + "allowed_mime_types": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "public" + ] + }, + "GetObjectInfoResponseContent": { + "type": "object", + "properties": { + "eTag": { + "type": "string" + }, + "size": { + "type": "number", + "nullable": true + }, + "mimetype": { + "type": "string" + }, + "cacheControl": { + "type": "string" + }, + "lastModified": { + "type": "string" + }, + "contentLength": { + "type": "number", + "nullable": true + }, + "httpStatusCode": { + "type": "number", + "nullable": true + } + } + }, + "ListObjectsRequestContent": { + "type": "object", + "properties": { + "prefix": { + "type": "string" + }, + "limit": { + "type": "number", + "nullable": true + }, + "offset": { + "type": "number", + "nullable": true + }, + "sortBy": { + "$ref": "#/components/schemas/SortBy" + } + }, + "required": [ + "prefix" + ] + }, + "MoveObjectRequestContent": { + "type": "object", + "properties": { + "bucketId": { + "type": "string" + }, + "sourceKey": { + "type": "string" + }, + "destinationKey": { + "type": "string" + }, + "destinationBucket": { + "type": "string" + } + }, + "required": [ + "bucketId", + "destinationKey", + "sourceKey" + ] + }, + "SignedUrlResult": { + "type": "object", + "properties": { + "signedURL": { + "type": "string" + }, + "path": { + "type": "string" + }, + "error": { + "type": "string" + } + }, + "required": [ + "path" + ] + }, + "SortBy": { + "type": "object", + "properties": { + "column": { + "type": "string" + }, + "order": { + "type": "string" + } + } + }, + "StorageErrorResponseContent": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "error": { + "type": "string" + }, + "statusCode": { + "type": "string" + } + } + }, + "UpdateBucketRequestContent": { + "type": "object", + "properties": { + "public": { + "type": "boolean" + }, + "file_size_limit": { + "type": "number", + "nullable": true + }, + "allowed_mime_types": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + } + }, + "required": [ + "public" + ] + }, + "UpdateObjectResponseContent": { + "type": "object", + "properties": { + "Key": { + "type": "string" + }, + "Id": { + "type": "string" + } + }, + "required": [ + "Id", + "Key" + ] + }, + "UploadObjectResponseContent": { + "type": "object", + "properties": { + "Key": { + "type": "string" + }, + "Id": { + "type": "string" + } + }, + "required": [ + "Id", + "Key" + ] + } + } + } +} \ No newline at end of file diff --git a/kiota-spike/spike-kiota.csproj b/kiota-spike/spike-kiota.csproj new file mode 100644 index 00000000..0435d50f --- /dev/null +++ b/kiota-spike/spike-kiota.csproj @@ -0,0 +1,41 @@ + + + + + netstandard2.1 + enable + latest + false + false + + false + false + false + $(NoWarn);CS1591;CS0618 + + false + false + + + + + + + + + + + + + + + + + + + diff --git a/kiota-testrun/Program.cs b/kiota-testrun/Program.cs new file mode 100644 index 00000000..e86a6d92 --- /dev/null +++ b/kiota-testrun/Program.cs @@ -0,0 +1,111 @@ +// Manual test-run for the Kiota-generated Supabase Storage client (SDK-1107). +// +// Verifies, against a LOCAL Supabase platform, the brief's reachable deliverables for Kiota: +// • HttpClient injection — we build the client over an externally-created HttpClient +// • real round-trip — ListBuckets / CreateBucket against the live Storage API +// • streaming upload — UploadObject from a FileStream via MultipartBody (no byte[] buffering) +// +// Not covered here (and why): +// • streaming *response* — the Smithy Storage model has no object-download op; the streaming- +// response deliverable lives in Functions.Invoke (needs a deployed edge function) — separate run. +// • Auth / PostgREST — Auth isn't modelled upstream; PostgREST value is the hand-written builder. +// +// Run: +// supabase start # from any local Supabase project +// supabase status # copy the service_role key + API URL +// SUPABASE_URL=http://127.0.0.1:54321 SUPABASE_KEY= dotnet run +// +// Defaults below use the well-known local demo key; override via env for your instance. + +using System.Text; +using Microsoft.Kiota.Abstractions; +using Microsoft.Kiota.Abstractions.Authentication; +using Microsoft.Kiota.Http.HttpClientLibrary; +using Supabase.Storage.Kiota; +using Supabase.Storage.Kiota.Models; + +var supabaseUrl = Environment.GetEnvironmentVariable("SUPABASE_URL") ?? "http://127.0.0.1:54321"; +var supabaseKey = Environment.GetEnvironmentVariable("SUPABASE_KEY") + ?? "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU"; + +Console.WriteLine($"Supabase URL : {supabaseUrl}"); +Console.WriteLine($"Storage base : {supabaseUrl}/storage/v1"); +Console.WriteLine($"Key : {supabaseKey[..12]}…\n"); + +// ── HttpClient injection ──────────────────────────────────────────────────── +// Externally-created HttpClient carrying the Supabase auth headers. Kiota uses THIS client +// (DI / IHttpClientFactory pattern) instead of creating its own. +var http = new HttpClient(); +http.DefaultRequestHeaders.Add("apikey", supabaseKey); +http.DefaultRequestHeaders.Add("Authorization", $"Bearer {supabaseKey}"); + +var adapter = new HttpClientRequestAdapter(new AnonymousAuthenticationProvider(), httpClient: http) +{ + BaseUrl = $"{supabaseUrl}/storage/v1" +}; +var client = new StorageApiClient(adapter); +Console.WriteLine("[✓] HttpClient injection — client built over an external HttpClient\n"); + +var bucketId = $"kiota-spike-{DateTime.UtcNow:yyyyMMddHHmmss}"; +var pass = 0; +var fail = 0; + +async Task Step(string name, Func action) +{ + try { await action(); Console.WriteLine($"[✓] {name}\n"); pass++; } + catch (Exception ex) { Console.WriteLine($"[✗] {name}\n {ex.GetType().Name}: {ex.Message}\n"); fail++; } +} + +// ── round-trip: list buckets ──────────────────────────────────────────────── +await Step("ListBuckets", async () => +{ + // Envelope fix: the response is a bare array; the generated client now returns + // List directly (previously an .Items envelope that never matched the wire + // shape, so this call silently returned 0 — the false-zero failure). + var buckets = await client.Bucket.GetAsync(); + Console.WriteLine($" server returned {buckets?.Count ?? 0} bucket(s)"); +}); + +// ── round-trip: create bucket ─────────────────────────────────────────────── +await Step($"CreateBucket ({bucketId})", async () => +{ + var resp = await client.Bucket.PostAsync(new CreateBucketRequestContent + { + Id = bucketId, + Name = bucketId, + Public = false + }); + Console.WriteLine($" created (response stream: {(resp is null ? "none" : "received")})"); + resp?.Dispose(); +}); + +// ── streaming upload: FileStream → MultipartBody (no byte[] buffering) ─────── +var objectName = "hello.txt"; +await Step($"UploadObject (streaming FileStream → {bucketId}/{objectName})", async () => +{ + // a real on-disk file, streamed — never read into a byte[] + var tmp = Path.GetTempFileName(); + await File.WriteAllTextAsync(tmp, $"streamed from Kiota test-run at {DateTime.UtcNow:O}\n"); + var sizeKb = new FileInfo(tmp).Length / 1024.0; + + await using var fileStream = File.OpenRead(tmp); // <-- streamed, not buffered + var multipart = new MultipartBody { RequestAdapter = adapter }; + multipart.AddOrReplacePart("cacheControl", "text/plain", "3600"); + multipart.AddOrReplacePart("metadata", "application/json", "{}"); + multipart.AddOrReplacePart("file", "text/plain", fileStream, objectName); + + var resp = await client.Object[bucketId][objectName].PostAsync(multipart); + Console.WriteLine($" uploaded {sizeKb:0.00} KB via StreamContent; key = {resp?.Key ?? "(none)"}"); + File.Delete(tmp); +}); + +// ── confirm the object landed ─────────────────────────────────────────────── +await Step("ListObjects (confirm upload)", async () => +{ + var listed = await client.Object.List[bucketId].PostAsync(new ListObjectsRequestContent { Prefix = "" }); + Console.WriteLine($" bucket now holds {listed?.Count ?? 0} object(s)"); +}); + +Console.WriteLine(new string('─', 60)); +Console.WriteLine($"Result: {pass} passed, {fail} failed"); +return fail == 0 ? 0 : 1; diff --git a/kiota-testrun/README.md b/kiota-testrun/README.md new file mode 100644 index 00000000..c2a6af12 --- /dev/null +++ b/kiota-testrun/README.md @@ -0,0 +1,53 @@ +# spike-kiota.TestRun — manual run of the Kiota client vs local Supabase + +Hand-written (ownable) console harness that drives the **Kiota-generated Storage client** +(`../kiota-spike`) against a **local Supabase platform**, to actually exercise the brief's +reachable deliverables rather than only reason about them. + +## What it verifies + +| Deliverable | How | +|---|---| +| **HttpClient injection** | client is built over an externally-created `HttpClient` (DI/`IHttpClientFactory` shape) carrying the `apikey` + `Authorization` headers | +| **Real round-trip** | `ListBuckets`, `CreateBucket` against the live Storage API | +| **Streaming upload** | `UploadObject` from a `FileStream` via Kiota `MultipartBody` — streamed, never read into a `byte[]` | +| confirm | `ListObjects` shows the uploaded object | + +**Not covered (by design):** +- *Streaming response* — the Smithy Storage model has no object-download operation; that + deliverable belongs to `Functions.Invoke` (`Task`), which needs a deployed edge function. +- *Auth / PostgREST* — Auth isn't modelled upstream; PostgREST's value is the hand-written builder. + +## Run it + +```bash +# 1. start a local platform (from any Supabase project dir; needs Docker) +supabase start +supabase status # note the API URL and the service_role key + +# 2. run the harness (from this folder) +SUPABASE_URL=http://127.0.0.1:54321 \ +SUPABASE_KEY= \ +dotnet run +``` + +Defaults (no env vars): `http://127.0.0.1:54321` and the well-known local **demo** service_role key. +If your CLI generated different keys, pass `SUPABASE_KEY` explicitly. + +Expected output ends with `Result: N passed, 0 failed`; each step prints `[✓]`/`[✗]` with detail. +Exit code is non-zero if any step fails (CI-friendly). + +## Status — executed against a local platform ✅ (with one real finding) + +All 4 steps pass. Confirmed end-to-end against the live API: +- **HttpClient injection** and **streaming upload** genuinely work — the uploaded object + (`hello.txt`, 61 bytes) is present on the server. + +**Finding the run surfaced (static analysis missed it):** `ListBuckets`/`ListObjects` print `0` +even though the data exists. The real Storage API returns **bare JSON arrays** +(`GET /bucket → [ {...} ]`), but the Smithy model wraps them (`ListBucketsOutput { items: [...] }`), +so the generated client deserializes an array into an object → `.Items == null` → **false zero, no +error**. Tool-independent (NSwag has the same envelope) and affects every SDK — a model-vs-production +mismatch to raise on `supabase/sdk`. See `../kiota-spike/evaluation-kiota.md` §10. + +> Isolated spike project: in `Supabase.sln` for convenience, **not referenced by `Supabase.csproj`**. diff --git a/kiota-testrun/spike-kiota.TestRun.csproj b/kiota-testrun/spike-kiota.TestRun.csproj new file mode 100644 index 00000000..03b0a74e --- /dev/null +++ b/kiota-testrun/spike-kiota.TestRun.csproj @@ -0,0 +1,23 @@ + + + + + Exe + net8.0 + enable + enable + Supabase.Spike.KiotaTestRun + false + + + + + + + + diff --git a/nswag-spike/.gitignore b/nswag-spike/.gitignore new file mode 100644 index 00000000..06aa1cef --- /dev/null +++ b/nswag-spike/.gitignore @@ -0,0 +1,4 @@ +# Spike tooling / build output — not part of the artifact +node_modules/ +bin/ +obj/ diff --git a/nswag-spike/README.md b/nswag-spike/README.md new file mode 100644 index 00000000..1da33824 --- /dev/null +++ b/nswag-spike/README.md @@ -0,0 +1,68 @@ +# NSwag codegen spike (C# SDK · SDK-1107) + +Evaluation of generating the C# SDK's transport + models from the shared Smithy models +(`supabase/sdk#51`), via the committed Smithy→OpenAPI artifacts and **NSwag**. + +> ⚠️ **This is a spike, not shippable code.** Everything under `generated/` is machine-emitted +> and **not owned/maintainable**. It lives in its own standalone project (`spike-nswag.csproj`, a +> separate assembly) added to `Supabase.sln` for visibility, but it is **not referenced by +> `Supabase.csproj`** and has analyzers disabled — so it does **not** affect the product's build, +> analyzers, or quality metrics. Do not reference it from the SDK. + +## Pipeline + +``` +Smithy model (supabase/sdk#51) ──smithy build──► *.openapi.json ──NSwag──► *Client.cs + (hand-authored, upstream) + patch-openapi.py (generated, this spike) +``` + +We consume the **committed OpenAPI** (`smithy-pr51/*.openapi.json`); we never run Smithy in C#. + +## Layout + +| Path | What | +|------|------| +| `smithy-pr51/` | Historical snapshot of the upstream source as evaluated (`supabase/sdk@feat/smithy-models`): `*.smithy` models, committed `*.openapi.json`, `patch-openapi.py`. Superseded by the fixes in `supabase/sdk#55`; kept as the record of what the spike ran against. | +| `generated/*.ready.json` | The OpenAPI actually fed to NSwag — the committed upstream artifacts, consumed **verbatim** (the former local wildcard patch is fixed upstream in `supabase/sdk#55`). | +| `generated/*Client.cs` | NSwag output — Storage / Functions / Database clients + models. **Generated, non-owned.** | +| `spike-nswag.csproj` | Standalone project (in the solution, isolated) that compiles the three clients — proves they build (netstandard2.1, System.Text.Json only). | +| `evaluation-nswag.md` | **Per-toolchain evaluation** — what's produced, good/bad, answers to the brief. | +| `findings/` | Supporting memos: the Smithy PR review + the two raw-spec spikes. | + +For the cross-toolchain comparison and overall recommendation, see the root +[`codegen-comparison.md`](../codegen-comparison.md). + +## Reproduce + +```bash +# tools: dotnet SDK + NSwag CLI +dotnet tool install --global NSwag.ConsoleCore +# generate each service (no local spec patching needed since supabase/sdk#55): +nswag openapi2csclient /input:generated/StorageService.ready.json /classname:StorageClient \ + /namespace:Supabase.Storage.Gen /output:generated/StorageClient.cs \ + /jsonLibrary:SystemTextJson /injectHttpClient:true /generateClientInterfaces:true \ + /generateNullableReferenceTypes:true /generateOptionalParameters:true /useBaseUrl:false \ + /generateDataAnnotations:false /operationGenerationMode:SingleClientFromOperationId +# (Functions/Database identical) +# generateDataAnnotations:false → no System.ComponentModel.DataAnnotations dependency +dotnet build spike-nswag.csproj # 0 warnings / 0 errors +``` + +## Conclusion (see `findings/` for the full case) + +- **Models: worth generating.** Clean, typed, irreducible data (`Bucket`, `FileObject`, signed-URL + responses, the `FilterOperator` enum). This is where cross-SDK drift bites and where generation + removes real recurring work. Concentrated in **Storage** — Functions/Database bodies are dynamic + (`Blob`/`byte[]`), so there are no meaningful models to generate there. +- **Operations: not worth it.** Each generated method is ~86 LOC of *un-refactored* transport — + the same logic our shared `Helpers.MakeRequest` already does once, inlined per operation. Refactor + it for DRY and it converges on our existing architecture; it also **lacks** our domain error + mapping (`FailureHint`), serializer injection, and dynamic headers. The SDK is already + thin-wrapper-shaped, so generated ops add a layer *beneath* a wrapper we write anyway. +- **The only transport idea worth stealing:** `HttpCompletionOption.ResponseHeadersRead` — a + one-line addition to `Core`, no codegen required. +- **Unspillable by any generator:** Storage streaming/progress/TUS, the PostgREST query builder, + Functions method-dispatch + streaming responses, and **all of Auth** (not modelled upstream). + +**Net:** take generated **models** (Storage-first); keep operations + transport hand-written on a +shared `Core`. Whole-client generation is a worse-factored copy of what we already own. diff --git a/nswag-spike/evaluation-nswag.md b/nswag-spike/evaluation-nswag.md new file mode 100644 index 00000000..65df349d --- /dev/null +++ b/nswag-spike/evaluation-nswag.md @@ -0,0 +1,165 @@ +# NSwag evaluation — answers to the spike brief (SDK-1107) + +Tool: NSwag 14.7.1 (`openapi2csclient`), input = committed Smithy→OpenAPI from `supabase/sdk#51`. +Settings: `SystemTextJson, injectHttpClient, generateClientInterfaces, nullableReferenceTypes, +optionalParameters, generateDataAnnotations:false, SingleClientFromOperationId`. +All generated code compiles clean on netstandard2.1 (see `spike-nswag.csproj`). + +Legend: ✅ works as-generated · 🟡 works only after a **model/patch** change (feeds back to +`supabase/sdk`) · ❌ not achievable with NSwag. + +## Live run (`../nswag-testrun`) — what actually happened against a local platform + +Running the generated client against `supabase start` (mirror of the Kiota run) was the most +informative step. Result: HttpClient injection ✅, **streaming upload ✅** (FileStream → +`FileParameter`/`StreamContent`, confirmed on the server), but **both list ops failed** — for two +distinct, serious reasons: + +1. **NSwag serializes every optional field at its default (no `WhenWritingNull`).** Requests carry + `file_size_limit:0`, `limit:0`, `offset:0`, `sortBy:null`, and the server rejects several: + - `CreateBucket` sends `file_size_limit:0` → a bucket that **rejects every upload** (`413`). We + had to set it explicitly to test uploads at all. + - `ListObjects` sends `limit:0` (`400 "limit must be >= 1"`) and `sortBy:null` + (`400 "sortBy must be object"`). + This is the **non-nullable-optional data-fidelity flaw** (see §3a) turned into **functional + breakage**: optional value types are non-nullable, default to `0`/`null`, and are always emitted. + Kiota models the same fields nullable and omits them, so its identical calls just worked. + *Fixable* (STJ `DefaultIgnoreCondition = WhenWritingNull` + nullable value types, or mark the + fields nullable upstream) — but **the default generated output does not work against the server.** + +2. **List responses fail to deserialize** — the shared model wraps arrays the API returns bare + (`ListBuckets`/`ListObjects`; see §10). NSwag **throws** `ApiException("Could not deserialize… + Status 200")` — notably **louder/safer than Kiota**, which silently returned an empty list for the + same bug. + +Net: the run confirms the headline capabilities (injection, streaming upload) *and* proves the +generated **request** DTOs are not usable as-is against Supabase without a serialization fix. + +**Update (July 2026):** both defects were fixed upstream in `supabase/sdk#55` and verified by a +rerun against the corrected artifacts: list operations deserialize (bare arrays, direct +`ICollection` returns), and `CreateBucket` works **without** `file_size_limit` — the spec now +types it `double?` and the server accepts `null` as unset, so the 413-bucket failure is gone. +`ListObjects` still returns 400: NSwag writes unset members as explicit nulls and the server +rejects `limit: null` (null-tolerance is per-field). The `WhenWritingNull` client configuration +therefore remains required — the generator-side half of the fix, unchanged. + +## Question-by-question + +### 1. Streaming uploads — ✅ (model gap, fixed upstream in `supabase/sdk#55`) +- **Multipart (`UploadObject`/`UpdateObject`): ✅ already streams.** Generated code builds + `MultipartFormDataContent` + `new StreamContent(file.Data)` from a `FileParameter(Stream)` — no + `byte[]` buffering of the file part. +- **Raw octet-stream body (`UploadChunk` TUS PATCH, Functions): ❌ as-shipped.** The body is a + `$ref` to a `format: byte` payload schema, so NSwag **JSON-serializes it** + (`JsonSerializer.SerializeToUtf8Bytes(body)` → `ByteArrayContent`) — non-streaming *and* + semantically wrong (base64). +- **Proven fix (model side):** when the requestBody is **inline** `type: string, format: binary` + (no `$ref`), NSwag emits `…Async(string fn, System.IO.Stream body, …)` + `new StreamContent(body)` + — **true streaming, zero buffering.** So NSwag *can* do streaming uploads; the shared model must + emit an inline binary body instead of a `$ref`-to-`format:byte` payload. +- **Fixed upstream** (`supabase/sdk#55`): the committed artifacts now emit inline binary for all + octet-stream bodies; regeneration produces the `Stream` signatures with no local patching. + +### 2. Streaming responses — ✅ as `Stream` (model gap, fixed upstream in `supabase/sdk#55`) +- **As-shipped: ❌.** Functions responses are `$ref` → `format: byte`, so NSwag returns + `Task` read via `ReadObjectResponseAsync` — fully buffered + base64. +- **Proven fix:** flipping the response schema `format: byte → binary` makes NSwag emit + `Task`, where `FileResponse.Stream` is the **raw response stream**, read via + `ReadAsStreamAsync` with `HttpCompletionOption.ResponseHeadersRead` — unbuffered streaming. +- **Caveat vs brief:** NSwag exposes a **`Stream`**, not `IAsyncEnumerable`. The brief + accepts "`IAsyncEnumerable` **or** `Stream`", so this qualifies. `supabase/sdk#55` + extends the byte→binary flip to Functions (and Database payloads); regeneration now yields + `Task` with no local patching. Live Functions verification remains open (needs a + deployed edge function). + +### 3. HttpClient injection — ✅ +Constructor is `public StorageClient(System.Net.Http.HttpClient httpClient)` (same pattern for +`FunctionsClient`/`DatabaseClient`). Accepts an externally created/`IHttpClientFactory` client. No +internally-created `HttpClient`. + +### 4. Middleware / handlers — ✅ +Two seams: (a) the injected `HttpClient` carries any `DelegatingHandler` pipeline (auth headers, +error-relay inspection); (b) generated `partial void PrepareRequest(...)` / `ProcessResponse(...)` +hooks per request/response, implementable in a hand-owned partial. Auth headers (apikey/JWT/ +`X-Client-Info`) are **not** modelled — they go here, hand-written. + +### 5. Multipart uploads — ✅ +Correct `MultipartFormDataContent` with explicit boundary and a streaming `StreamContent` file +part (see Q1). Non-file parts (`cacheControl`, `metadata`) are added as `StringContent`/ +`ByteArrayContent`. Wart: they're generated as **required** (throw if null) because the injected +multipart schema marks them so — a model refinement, not a blocker. + +### 6. Auth flows — ❌ (not modelled) +**Auth is absent from `supabase/sdk#51`.** Nothing to generate. Even once modelled, the +investigation stands: token/OTP/OAuth-redirect/session-refresh/MFA/PKCE are behavioral and +largely inexpressible in Smithy (the PR itself flags Auth as possibly unsuitable). Expected split: +**HTTP operations generatable; the session/refresh loop + PKCE + provider validation stay +hand-written.** Cannot be verified until models exist → **model gap to raise.** + +### 7. PostgREST query builder — 🟡 minimal +Codegen produces: the 7 transport methods (`SelectRows`/`InsertRows`/… + RPC), `filters`/`args` +as `IDictionary`, and a typed **`FilterOperator`** enum (all 24 operators). It does +**not** and cannot produce the fluent builder (`.Select()/.Eq()/.Order()`) — bodies are `byte[]` +(`Blob`, dynamic row shape). **The query builder + row typing stay entirely hand-written**; codegen +helps only at the enum + raw-transport layer. Matches the "PostgREST ~0%" prior finding. + +### 8. AOT / trimming — ❌ as-generated +- Serialization is **reflection-based System.Text.Json** (`JsonSerializer.Deserialize(…, options)`, + 13 call sites, **0** `JsonSerializerContext`/`[JsonSerializable]` source-gen). Not trim/NativeAOT + safe without a hand-added source-gen context — **NSwag has no STJ source-gen emitter.** +- `ConvertToString` for enums uses `System.Reflection` (`GetDeclaredField` + + `GetCustomAttribute`) — a secondary trim hazard. +- Verdict: needs post-processing (source-gen `JsonSerializerContext`) or a different tool to be + AOT-clean. This is the weakest area for NSwag against the "idiomatic" bar. + +### 9. Unity compatibility — 🟡 partial +Targets `netstandard2.1` → Unity-consumable, and it compiled clean. But the same reflection-STJ + +enum-reflection means **IL2CPP/AOT is not clean** for the same reasons as Q8. Framework-reachable, +not AOT-verified. (Consistent with the original investigation; treat as out-of-scope until Q8 is +solved, since the fix is the same.) + +### 10. Model gaps found → raised on `supabase/sdk` (fixed in #55, except Auth and 200-only) +| Gap | Impact | Suggested model/patch fix | +|---|---|---| +| Functions/TUS request bodies are `$ref` → `format:byte` | streaming upload broken (JSON-serialized) | emit **inline** `type:string,format:binary` requestBody (no `$ref`) | +| Functions response `format:byte` | streaming response buffered/base64 | extend `patch-openapi.py` byte→binary to Functions responses | +| `{wildcardPath+}` greedy label | invalid C# identifier (`wildcardPath+`) → 24 compile errors | strip the RFC-6570 `+` in `patch-openapi.py`, or fix the `@httpLabel` emission | +| Multipart non-file parts marked required | forces non-null `cacheControl`/`metadata` | mark optional in the model | +| **Auth unmodelled** | can't evaluate/generate Auth at all | add Auth models (or formally scope it out as hand-written) | +| Write ops model `200` only | clients must tolerate 204 empty bodies | documented upstream; handle in hand-written seam | + +**Update (July 2026):** the first four rows are fixed upstream in `supabase/sdk#55` (verified by +rerunning generation and the live harness against the corrected artifacts — no local `ready.json` +patching needed anymore). **Auth** and the `200`-only write ops remain open. + +## Recommendation — **ADAPT** (models-first, hand-written operations/transport) + +**Adopt generation for the low-behavior, high-drift layer; keep behavior hand-written.** + +- **Generate (worth it):** wire **models/DTOs** (Storage `Bucket`/`FileObject`/signed-URL/response + types; the `FilterOperator` enum). Irreducible data, where cross-SDK drift bites, near-zero + wrapper cost. Concentrated in Storage (Functions/Database bodies are dynamic → nothing to model). +- **Do not generate (net-negative):** the **operation layer**. Each method is ~86 LOC of + un-refactored transport that DRYs back into the SDK's existing `MakeRequest`, minus our + `FailureHint` error mapping / serializer injection / dynamic headers. On an already + thin-wrapper-shaped SDK, generated ops add a layer *beneath* a wrapper we write anyway. +- **Adopt one transport technique:** add `HttpCompletionOption.ResponseHeadersRead` to the shared + `Core` transport. +- **Stays hand-written regardless:** Storage streaming/progress/TUS ergonomics, the PostgREST + query builder, Functions method-dispatch, and **all of Auth**. + +**Why not "adopt" (whole client):** streaming needs model fixes *and* still yields `Stream`/ +`FileResponse` we'd wrap; AOT/trimming fails (reflection STJ); the operation layer is worse-factored +than what we own. **Why not "reject":** the model slice is a real, low-cost win *if* a validated +OpenAPI contract is maintained centrally (from whichever IDL emits it) — C# reuses it. +Standalone-for-C# only, the pipeline overhead (contract upstream, patches, naming template, +source-gen for AOT) likely exceeds the value. + +**Net:** NSwag against these specs is a viable **models generator** and a poor **whole-client +generator**. Draw the line at models vs operations; feed the Q10 gaps back to `supabase/sdk` so +every SDK benefits. + +The adoption strategy built on this verdict — two stages, drift monitoring, consumer impact of +integrating generated types into the published API, and the conditions/reversal criteria — is +defined in the root [`codegen-comparison.md`](../codegen-comparison.md); this document is the +tool-level evidence. diff --git a/nswag-spike/findings/nswag-spike-findings.md b/nswag-spike/findings/nswag-spike-findings.md new file mode 100644 index 00000000..9e970485 --- /dev/null +++ b/nswag-spike/findings/nswag-spike-findings.md @@ -0,0 +1,207 @@ +# NSwag Spike — Auth (GoTrue) OpenAPI → C# Client + +> Concrete follow-up to `codegen-investigation-findings.md` §8/§11 (Gate 2). Goal: stop +> hypothesizing and run a real toolchain against the team's **hand-maintained** Auth spec +> (`~/Downloads/openapi.yaml`, OpenAPI 3.0.3, 3928 lines) to see what NSwag actually emits, +> what's usable, and where the boundary falls. + +Reproduction lives in `_nswag-spike/` (spec preprocessor, generated `.cs`, build harness). + +## TL;DR + +- NSwag **cannot ingest the spec as-shipped** — two blockers, one a tool bug, one a spec bug. +- After a ~30-line preprocessor, it generates a **clean-compiling** 11k-line client + (System.Text.Json, injected `HttpClient`) — so "it runs" is a yes. +- But the output quality **splits hard along the models/operations line**, exactly as the A/B + framework predicted: + - **Models: usable-ish** (15 named schemas → real classes; fixable naming/nullability warts). + - **Operations: unusable** — garbage method names, invented request/response types, one giant + method where we hand-write five, and *zero* of the ergonomic/stateful behavior. +- Root cause is **not NSwag**. It's the spec: **0 `operationId`s** and only **15 named schemas + against 103 inline `type: object` bodies**. Codegen quality is capped by spec richness, and + this spec is model-rich / operation-poor. + +**Verdict for the RFC:** this is direct evidence for the **"A for models, B for operations"** +hybrid. A whole-client generator applied to *this* spec produces something no maintainer would +own. + +--- + +## 1. Getting the spec through the tool at all (2 blockers) + +Environment: `dotnet 10.0.300`, `NSwag.ConsoleCore 14.7.1` (NJsonSchema 11.6.1). + +### Blocker A — NSwag bug on reusable `responses` components (spec is valid) +The spec uses standard reusable responses: every operation does +`$ref: "#/components/responses/BadRequestResponse"` etc. NSwag 14.7.1 throws: + +``` +System.InvalidCastException: Unable to cast object of type 'NSwag.OpenApiResponse' +to type 'NJsonSchema.JsonSchema'. +``` + +This is a **known NSwag/NJsonSchema limitation**, not a spec error — `$ref` into +`#/components/responses/*` is textbook OpenAPI 3.0. 101 such refs in the spec. + +### Blocker B — genuine spec bug (malformed `$ref`) +`/user/identities/{identityId}` DELETE puts a **response component in a schema slot**: + +```yaml +401: + content: + application/json: + schema: + $ref: "#/components/responses/UnauthorizedResponse" # <-- should be schemas/ErrorSchema +``` + +A response component is not a schema. This is a latent bug in the hand-maintained spec that a +codegen pipeline surfaces immediately (2 occurrences: 401 + 403 on that op). + +### Workaround +`_nswag-spike/inline-responses.js` (~30 LOC): inline the 101 `responses` refs into each +operation and rewrite the 2 malformed schema-refs to `ErrorSchema`. This is a **pre-processing +step the pipeline would have to own and maintain** — first tax item. + +--- + +## 2. Does it compile? Yes — with the right knobs + +First pass (`/classname` single name, default op-grouping) **did not compile**: NSwag grouped +operations by tag into 3 `partial` fragments of the same class and emitted its helper region +(`ProcessResponse`, `ReadObjectResponseAsync`, `ConvertToString`, …) **three times** → 99 +duplicate-member errors. Also needed a `System.ComponentModel.Annotations` reference on +netstandard. + +Fix: `/operationGenerationMode:SingleClientFromOperationId`. Result: +**11,085 lines, one client class, builds clean (0 warnings/errors)** on `netstandard2.1`. + +Generation settings used (all "idiomatic" per the assignment): +`/jsonLibrary:SystemTextJson /injectHttpClient:true /generateClientInterfaces:true +/generateNullableReferenceTypes:true /generateOptionalParameters:true /useBaseUrl:false`. + +So: **injectable `HttpClient` ✔, System.Text.Json ✔, interface ✔.** The transport plumbing +NSwag emits is competent (`SendAsync` + `HttpCompletionOption.ResponseHeadersRead`, per-status +deserialization, `PrepareRequest`/`ProcessResponse` partial seams). + +--- + +## 3. Output quality — split along models vs operations + +### 3a. Models — usable, with warts (the 15 named schemas) +`UserSchema`, `AccessTokenResponseSchema`, `MFAFactorSchema`, `IdentitySchema`, etc. render as +real, individually-named classes. Problems, all fixable via templates/spec edits: + +| Issue | Generated | Hand-written today | +|---|---|---| +| **Naming** | `Email_confirmed_at`, `Is_anonymous`, `New_email` (pascalizes one token, keeps snake underscores) | `EmailConfirmedAt`, `IsAnonymous` (proper) | +| **Nullability of optional timestamps** | `DateTimeOffset Email_confirmed_at` — **non-nullable**; absent → `0001-01-01`, loses null | `DateTime? EmailConfirmedAt` | +| **Untyped bags** | `object App_metadata` | `Dictionary AppMetadata` | +| **Type name** | `UserSchema` (component name leaks) | `User` | +| **Extras** | `[JsonExtensionData] AdditionalProperties` on every model | n/a | + +The nullability one is a **data-fidelity bug**, and it traces to the spec (fields not marked +`nullable: true`). Verdict: **models are the part codegen does adequately** — deterministic, +low-behavior, and where cross-SDK field drift actually bites. Warts are template/spec work, not +fundamental. + +### 3b. Operations — unusable as emitted +**0 `operationId`s in the spec** → NSwag falls back to `{lastPathSegment}{METHOD}` naming: + +``` +VerifyGETAsync / VerifyPOSTAsync / VerifyPOST2Async +ClientsGETAsync / ClientsGET2Async / ClientsDELETEAsync +Authorize2Async / Authorize3Async / CallbackGETAsync +``` + +**Only 15 named schemas vs 103 inline `type: object` bodies** → NSwag invents type names for +every request/response envelope: + +``` +Body, Body2 … Body23 (request bodies) +Response, Response2 … Response15 (response envelopes) +Anonymous, Anonymous2, Weak_password2 (nested inline objects) +Task RecoverAsync(...) (bodies too thin to type at all) +``` + +No maintainer accepts `Task Token2Async(Grant_types2 grant_type, Body11 body)`. + +### 3c. The flagship case: `/token` +Spec has **one** `POST /token` operation whose body is a single `type: object` merging the +fields of **five different grant flows** (password / refresh_token / id_token / pkce / web3). +NSwag faithfully emits **one** method: + +```csharp +Task TokenAsync(Grant_type grant_type, Body? body = null, ...) +``` + +`Body` has every field of every flow, all optional (`Refresh_token`, `Password`, `Email`, +`Id_token`, `Auth_code`, `Code_verifier`, `Message`, `Signature`, `Chain`, …). The caller gets +zero guidance on which combination is legal. + +Compare the hand-written SDK, which splits the same endpoint into **five ergonomic methods**: +`SignInWithEmail`, `SignInWithPhone`, `SignInWithIdToken`, `ExchangeCodeForSession`, +`RefreshAccessToken`. A generator **cannot** produce that split — the shape isn't in the spec. + +### 3d. What's missing entirely (the hand-written value, §3/§7b of prior doc) +None of this is in the generated client, and none of it *can* be from this spec: +- **PKCE**: `SignInWithOtp`/`ResetPasswordForEmail` generate the code challenge/verifier and + return a `PasswordlessSignInState`/`ResetPasswordForEmailState`. Generated `OtpAsync` returns + `Response2` and does none of it. +- **CAPTCHA** `gotrue_meta_security` wrapping, **provider validation** + (`SignInWithIdToken` throws on unsupported providers), **SSO XOR** (providerId vs domain), + **dual-shape parsing** (`SignUpWithEmail` returns `Session` *or* `User`). +- **Auth/headers**: no apikey/`Authorization: Bearer`/`X-Client-Info`/dynamic-header merging. + You'd wire it via the `PrepareRequest` partial or a `DelegatingHandler` — i.e. hand-written. +- **Error model**: generated code `throw`s `ApiException` per status. SDK maps to + `GotrueException` + `FailureHint` reason codes. Different contract. + +### 3e. Bonus: codegen faithfully reproduces spec bugs +The spec swaps 401/403 on `/token` (401→ForbiddenResponse, 403→UnauthorizedResponse). The +generated code dutifully throws `"HTTP Forbidden response."` on 401 and vice-versa. Codegen +launders spec errors into shipped code — an argument for models-only generation where the blast +radius is contained. + +--- + +## 4. Maintainability read + +- **Regen seam works for models**: `partial` classes + `PrepareRequest`/`ProcessResponse` hooks + are a real seam (NSwag's strength per §7c). You could own auth/error behavior in the partial + half and regenerate the model half. +- **But operations fight the seam**: to make `TokenAsync` into `SignInWithEmail` you're not + extending a partial, you're **hiding/wrapping** generated garbage behind a second hand-written + facade — i.e. you maintain *both* the generated op layer and the ergonomic layer. That's worse + than today's single hand-written `Api.cs`. +- **Pre-processing tax is permanent**: the response-inlining + malformed-ref fixes must run on + every spec update, and spec bugs (§1B, §3e) become C# bugs unless caught upstream. + +--- + +## 5. How this resolves the framework's Gate 2 + +> Gate 2: are specs rich enough to render idiomatic operations, or only structure? + +**Answer for Auth: only structure, and only partially.** The spec is **model-rich / operation- +poor** (15 named schemas, but 0 operationIds and 103 anonymous bodies). Per the framework, "mostly +behavioral / spec can't express it → B strictly dominates on operations." Confirmed empirically. + +**Recommended boundary (matches prior doc §11 hybrid):** +- **Models → A (NSwag or any deterministic tool).** Real value, deterministic, catches upstream + field drift. Needs template polish (naming, nullability) + spec hygiene. +- **Operations + transport → B (hand-written on owned `Core`).** Where behavior lives; the spike + shows generation here is a net negative. + +**Cheapest high-value config, if we adopt any of this:** run NSwag/NJsonSchema in **schema-only +mode** (`openapi2csclient` → DTOs, or NJsonSchema directly) to emit *just* the 15 models, and +leave `Api.cs` hand-written against `Core`. + +## 6. Prerequisites before codegen is even fair to evaluate again +These are **spec fixes**, independent of tool choice, and would benefit every language SDK: +1. Add `operationId` to all ~60 operations (kills the `VerifyPOST2Async` naming). +2. Promote the 103 inline `type: object` bodies to **named component schemas** (kills + `Body11`/`Response15`). +3. Mark optional fields `nullable: true` (fixes the timestamp data-fidelity bug). +4. Fix the malformed `$ref` (§1B) and the 401/403 swap (§3e). + +Without (1)+(2), *no* toolchain (NSwag, Kiota, TypeSpec-emitter) can produce idiomatic +operations — the information simply isn't in the document. diff --git a/nswag-spike/findings/nswag-spike-storage-findings.md b/nswag-spike/findings/nswag-spike-storage-findings.md new file mode 100644 index 00000000..5c3da4d6 --- /dev/null +++ b/nswag-spike/findings/nswag-spike-storage-findings.md @@ -0,0 +1,169 @@ +# NSwag Spike #2 — Storage, and isolating manual-spec vs codegen issues + +> Companion to `nswag-spike-findings.md`. Same tool/config (NSwag.ConsoleCore 14.7.1, +> System.Text.Json, injected HttpClient), different spec: `~/Downloads/api.json` = +> **Supabase Storage API**, OpenAPI 3.0.3, **machine-generated** (Fastify/JSON-schema; schema +> names `def-0`, `def-1`; `title: authSchema`). Reproduction in `_nswag-spike/` +> (`storage.pretty.json`, `StorageGeneratedClient.cs`). +> +> **Purpose:** the Auth spec is hand-written. By running an *auto-generated* spec through the +> same pipeline, we separate "problems caused by hand-authoring" from "problems inherent to +> spec→C# codegen / the tool." + +## TL;DR + +Running the two specs side by side sorts every problem into three buckets: + +- **Manual-spec-only (Auth):** the two *ingest blockers* — NSwag's cast bug on reusable + `responses` components, and a malformed `$ref`. **Storage hit neither** → these were artifacts + of hand-authoring style, not of codegen. +- **Spec-shape, common to BOTH:** garbage operation names + invented request/response types + + missing behavior. **Root cause identical in both specs: 0 `operationId`s and almost no named + schemas.** This is the real, tool-independent ceiling. +- **Machine-spec-only (Storage):** *new* hard failures that make the output **not even compile** — + `4XX`/`5XX` status ranges and `{*}` wildcard path params — plus massive surface bloat. + +**Net:** neither spec makes *operation* codegen viable. The auto-generated spec is actually +**worse** than the hand-written one for codegen. The manual-vs-generated axis is not what decides +this — spec richness (operationIds + named schemas) is. Confirms the "**A for models, B for +operations**" boundary from both prior docs. + +--- + +## 1. Spec profile — auto-generated, but thinner than Auth + +| Metric | Auth (hand-written) | Storage (machine-generated) | +|---|---:|---:| +| Operations | ~60 | **110** | +| `operationId`s | **0** | **0** | +| Named component schemas | 15 | **3** (`def-0/1/2` = auth, error, vectorQuery) | +| Reusable `responses` components | 5 (→ Blocker A) | **0** | +| Inline `type: object` bodies | 103 | 94 | +| Wildcard `{*}` path params | none | **many** (`/object/{bucketName}/{*}`, `/s3/{Bucket}/{*}`, …) | +| `4XX`/`5XX` status ranges | no | **yes** | + +Key point: being machine-generated did **not** give it operationIds or named request/response +schemas. It's a Fastify route dump — every route's body/response is an inline schema, so there's +nothing for a generator to name. It's *more* model-poor than the hand-written spec (3 vs 15). + +Surface bloat: the spec exposes `s3/*`, `iceberg/*`, `vector/*`, `cdn/*`, `render/*`, plus +`HEAD`/`OPTIONS` twins of most routes — **110 operations** vs the handful the C# SDK actually +implements (bucket CRUD, object upload/download/list/move/copy, signed URLs). Generating the +whole spec produces a client that is mostly API the SDK has no intention of surfacing. + +--- + +## 2. Ingest: Storage sailed past the manual-spec blockers + +Auth needed a ~30-line preprocessor for two things; **Storage needed none of it:** + +- **Blocker A (NSwag cast bug on `$ref` → `#/components/responses/*`):** Storage has **0** + reusable responses → not triggered. This blocker was a property of how the Auth spec was + *organized by hand*, not of codegen. +- **Blocker B (malformed `$ref`, response-in-schema-slot):** a hand-authoring mistake. Absent + here. + +So NSwag generated the Storage file in one shot (13,671 lines). **First isolation result: both +ingest blockers were manual-spec-specific.** + +--- + +## 3. But the output does NOT compile — two machine-spec-specific bugs + +Auth compiled after config fixes. Storage produced **214 compile errors** that are *inherent to +this spec's content*, not config: + +### 3a. `4XX` / `5XX` status ranges → invalid C# +Fastify emits range status keys. NSwag renders them literally: + +```csharp +else if (status_ == 4XX) // CS1525 / CS1073: 4XX is not a number +{ + var objectResponse_ = await ReadObjectResponseAsync(...); +``` + +### 3b. Wildcard `{*}` path param → invalid identifier +The catch-all route param becomes a parameter literally named `*`: + +```csharp +Task ObjectGETAsync(string bucketName, string *, CancellationToken ...); // CS1001 +``` + +…and the same `*` leaks into the URL builder. Every wildcard route (a large fraction of the 110) +is broken this way. + +Neither bug appeared in Auth. **Second isolation result: the machine-generated spec introduces +its own class of non-compiling output** (range statuses + wildcard routes) that the hand-written +one didn't. + +--- + +## 4. Operations: identical failure mode in both (the tool-independent ceiling) + +With **0 operationIds**, NSwag falls back to `{lastPathSegment}{METHOD}` + numeric +disambiguation — same as Auth, arguably worse due to HEAD/OPTIONS twins: + +``` +S3GETAsync / S3GET2Async / S3GET3Async / S3GET4Async +PublicGETAsync / PublicGET2Async / PublicGET3Async +AuthenticatedHEADAsync / AuthenticatedHEAD2Async / AuthenticatedHEAD3Async +ResumableOPTIONSAsync / ResumableOPTIONS2Async +``` + +(The `/vector/*` methods got clean names — `CreateIndexAsync`, `QueryVectorsAsync` — *only* +because those paths are RPC-style verbs, i.e. accidental, not from opIds.) + +**Response typing is nearly absent:** of 110 methods, **81 return bare `Task`** (no typed body) +and only 29 return a `Task<...>`. The spec doesn't type its responses, so the generated client +gives callers nothing back for most calls. + +**Third isolation result: the operation-layer garbage is identical across a hand-written and a +machine-generated spec. It is driven purely by missing operationIds + unnamed bodies — not by who +wrote the spec, and not by NSwag.** + +--- + +## 5. Models: worse names than Auth, and the real value is unspillable anyway + +The 3 named schemas → `Def0`, `Def1`, `Def2`. Inline objects → a swarm of positional names: +`Buckets`, `Buckets2`, `Buckets3`, `Created_at`, `Created_at2`, `Created_at3`, `Metadata4`, +`SortBy2`, `Id3`, `File_size_limit2`, … A couple got title-based names (`BucketSchema`, +`ObjectSchema`), but most are unusable. + +Compare hand-written Storage models: `Bucket`, `FileObject`, `FileObjectV2` — clean, owned. + +And per the original investigation (§3/§5): Storage's actual value is **`ProgressableStreamContent`, +`HttpClientProgress`, and TUS resumable upload** — none of which is expressible in the spec or +emittable by any generator. NSwag turned the resumable-upload routes into broken `Resumable*Async` +stubs (the very routes hit hardest by the `{*}` bug). + +--- + +## 6. Conclusion — what "isolating manual-spec issues" actually showed + +The manual-vs-generated distinction explains **only the ingest blockers**, and it cuts the +*opposite* way from the intuition that "a machine-generated spec will be cleaner": + +| Bucket | Issues | Fix owner | +|---|---|---| +| **Manual-spec only** | NSwag responses-`$ref` cast bug; malformed `$ref` | spec authoring / preprocessor | +| **Common (spec-shape)** | garbage op names; invented `Body`/`Response`/`Def`/`Buckets2` types; untyped responses; no behavior | **upstream spec: add operationIds + named schemas** | +| **Machine-spec only** | `4XX`/`5XX` non-compile; `{*}` wildcard non-compile; surface bloat (s3/iceberg/vector, HEAD/OPTIONS) | spec dialect / generator config | + +**The decisive variable is spec richness, not authorship.** Both specs have 0 operationIds and +near-zero named request/response schemas, so both produce unusable operation layers regardless of +tool. The auto-generated Storage spec is *worse* for codegen than the hand-written Auth spec: +fewer named schemas, non-compiling range/wildcard constructs, and 110 mostly-irrelevant routes. + +Recommendation is unchanged and reinforced: **generate models only** (and even then, expect to +polish naming/nullability and fix the spec), **hand-write operations + transport on owned `Core`.** +For Storage specifically, the highest-value code (streaming/progress/TUS) is out of codegen's +reach entirely. + +### Prerequisite spec fixes (help every language SDK, independent of tool) +1. Add `operationId` to all operations — kills `S3GET4Async` / `VerifyPOST2Async` naming. +2. Promote inline bodies/responses to named component schemas — kills `Def1` / `Buckets2` / + `Response15`; enables typed returns. +3. Replace `4XX`/`5XX` range statuses with concrete codes (or accept per-tool patching). +4. Represent catch-all `{*}` routes with named path params (`{path}`) so params are valid C#. +5. Trim/segment the emitted surface to what each SDK ships (tags or a filtered spec). diff --git a/nswag-spike/findings/smithy-pr51-findings.md b/nswag-spike/findings/smithy-pr51-findings.md new file mode 100644 index 00000000..f266c75f --- /dev/null +++ b/nswag-spike/findings/smithy-pr51-findings.md @@ -0,0 +1,95 @@ +# Smithy PR #51 review — what's generated, how, and from which source + +> Reviewing `supabase/sdk#51` ("feat(smithy): add canonical Smithy models for APIs", author +> `grdsdev` / Guilherme Souza, branch `feat/smithy-models`, state OPEN, marked **DO NOT MERGE**). +> Context: other teams are exploring Smithy, which has **no C# emitter** — so the question is what +> this PR actually gives the C# SDK. Artifacts pulled into `_nswag-spike/smithy-pr51/`. + +## Answers to the three questions + +### From which source? +**Smithy IDL** (`smithy/model/*.smithy`) is the source of truth — hand-written models, *not* +derived from the existing SDK code or the live server. Originated in the **Swift spike** +([supabase-swift#1047](https://github.com/supabase/supabase-swift/pull/1047)) and promoted to the +shared `supabase/sdk` repo so every SDK team works from the same models. Covers **Storage, +Functions, Database (PostgREST)**. **Auth is explicitly not modelled yet** (PR flags OAuth +redirects + cookie session mgmt as possibly unsuitable for Smithy). + +### How was it generated? +`smithy build` (AWS Smithy CLI, restJson1 protocol) → OpenAPI 3.0 → then a **`patch-openapi.py` +post-processor** fixes two things Smithy can't express: +1. `@streaming blob` emits `format: byte` (base64) → rewritten to `format: binary`. +2. No native `multipart/form-data` in Smithy → the script **injects** the `UploadObject`/ + `UpdateObject` multipart request bodies straight into the OpenAPI JSON. + +The **patched OpenAPI files are committed** (`smithy/openapi/*.openapi.json`) precisely so +non-Smithy teams can consume them **without installing Smithy**. → **This is the C# path: +`Smithy → OpenAPI (committed) → NSwag/Kiota/TypeSpec`.** We never touch Smithy. + +### What's generated? (and does it work for C#?) +I ran the committed **StorageService.openapi.json** through the same NSwag pipeline as the earlier +spikes. **Result: dramatically better — usable.** + +| | Raw Storage `api.json` (Fastify) | Auth `openapi.yaml` (hand) | **Smithy PR#51 Storage** | +|---|---|---|---| +| operationIds | 0 | 0 | **20/20** | +| Named req/resp schemas | 3 | 15 | **26** | +| Method names | `S3GET4Async` | `VerifyPOST2Async` | **`ListBuckets`, `CreateSignedUrl`, `UploadObject`, `CreateTusUpload`** | +| Typed returns | 29/110 | partial | **all non-void ops** (`Task`) | +| Surface | 110 ops (s3/iceberg/vector bloat) | ~60 | **20 ops, curated to real SDK** | +| Generated size | 13,671 LOC | 11,085 LOC | **2,889 LOC** | +| Compiles? | ✗ 214 errors | ✓ (after config) | **✓ after a 1-line patch** | + +**The one blocker:** Smithy's greedy path label `{wildcardPath+}` carries the RFC-6570 `+` +modifier into the C# parameter name → `string wildcardPath+` (invalid identifier), 24 cascading +errors. A single `sed`/patch (`wildcardPath+` → `wildcardPath`, 10 occurrences) makes it +**compile clean (0 warnings/0 errors)**. This is a generic post-gen patch, same category as the +existing `patch-openapi.py` steps — trivial to fold in. + +## What this settles vs. the prior spikes + +Our two earlier findings were: (a) NSwag/C# is fine; (b) the *specs* were the ceiling (no +operationIds, unnamed bodies). PR #51 **removes that ceiling for Storage/Functions/PostgREST**: +because Smithy operations are named shapes, the generated OpenAPI has operationIds + named +schemas by construction, and NSwag then emits idiomatic, typed, compilable C#. The "spec quality" +experiment I proposed is effectively *already done upstream* — and it works. + +So the earlier verdict updates: +- **Models + operation *signatures*: now genuinely generatable** for the 3 modelled services (was + the open question). This is real, not hypothetical. +- **Boundaries unchanged / reconfirmed by the PR's own "Known Limitations":** + - **Streaming / multipart / TUS** are *not* expressible in Smithy — they exist only because + `patch-openapi.py` hand-injects them. So the transport for Storage's hard part is still + manually authored, just relocated into a Python patch script rather than C#. + - **PostgREST bodies are `Blob`** (row shape is dynamic) and the **query-builder (`.eq()`, + `.like()`) stays hand-written by design** — matches our "PostgREST ~0% generatable" finding. + Codegen gives you the transport skeleton + the `FilterOperator` enum, nothing more. + - **Functions**: one Smithy op per HTTP method → **5 `InvokeFunction*` operations**; the client + must hand-dispatch on `method` at runtime. The streaming-response feature is still net-new. + - **Auth not modelled**, and called out as maybe-unsuitable — i.e. the largest hand-written + service (5,497 LOC, the session/refresh/MFA/PKCE logic) is exactly what stays hand-written. + - **Write ops model 200 only** (Smithy needs one success code) though PostgREST returns + 204/200 → generated clients must tolerate empty bodies (a correctness caveat to handle in the + hand-written seam). + +## On "should we try another toolchain?" — now with data +The README's C# suggestion is **Kiota or `@typespec/http-client-csharp`**, notably **not NSwag**. +But our spike shows **NSwag consumes the committed OpenAPI cleanly** (one patch) and emits plain, +ownable, System.Text.Json + injected-HttpClient code with **no runtime dependency** — which is +better aligned with "plain ownable OSS code" than Kiota (`Microsoft.Kiota.Abstractions` runtime +dep) or the TypeSpec emitter (`System.ClientModel`, Azure style). Recommendation stands: **NSwag +against these OpenAPI artifacts is the strongest C# option**; a Kiota bake-off is only warranted +if the org mandates it, and it starts at a dependency-footprint disadvantage. + +## Suggested next steps +1. **Confirm the pipeline end-to-end** on Functions + Database OpenAPI too (Storage done here); + expect the same `{wildcardPath+}`/path-label patch to be the only friction. +2. **Feed the `wildcardPath+` bug back to the PR** — it breaks every generator that isn't RFC-6570 + aware, so it belongs in `patch-openapi.py` (or fix the Smithy `@httpLabel` greedy-trait + emission), not in each SDK's local workaround. +3. **Decide the C# boundary now** with real inputs: generate **models + operation signatures** + from these OpenAPI files; keep **streaming/TUS, PostgREST query-builder, Functions dispatch, + and all of Auth** hand-written on `Core`. This is the "A for models+transport-skeleton, B for + behavior" hybrid, now backed by a compiling artifact. +4. **Raise Auth**: since it's unmodelled and the biggest hand-written surface, the C# spike's + honest scope is "codegen helps Storage/Functions/PostgREST transport; Auth stays hand-written." diff --git a/nswag-spike/generated/DatabaseClient.cs b/nswag-spike/generated/DatabaseClient.cs new file mode 100644 index 00000000..5096b3f1 --- /dev/null +++ b/nswag-spike/generated/DatabaseClient.cs @@ -0,0 +1,1267 @@ +//---------------------- +// +// Generated using the NSwag toolchain v14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) +// +//---------------------- + +#nullable enable + +#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended." +#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." +#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' +#pragma warning disable 612 // Disable "CS0612 '...' is obsolete" +#pragma warning disable 649 // Disable "CS0649 Field is never assigned to, and will always have its default value null" +#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... +#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." +#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'" +#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant" +#pragma warning disable 8600 // Disable "CS8600 Converting null literal or possible null value to non-nullable type" +#pragma warning disable 8602 // Disable "CS8602 Dereference of a possibly null reference" +#pragma warning disable 8603 // Disable "CS8603 Possible null reference return" +#pragma warning disable 8604 // Disable "CS8604 Possible null reference argument for parameter" +#pragma warning disable 8625 // Disable "CS8625 Cannot convert null literal to non-nullable reference type" +#pragma warning disable 8765 // Disable "CS8765 Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes)." + +namespace Supabase.Database.Gen +{ + using System = global::System; + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial interface IDatabaseClient + { + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Function arguments — each entry becomes a query parameter. + ///
Keys and value formats are defined by the PostgreSQL function signature. + /// CallRpcGet 200 response + /// A server side error occurred. + System.Threading.Tasks.Task CallRpcGetAsync(string functionName, string? select = null, System.Collections.Generic.IDictionary? args = null, string? accept_Profile = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// e.g. "params=single-object" — treat the entire body as a single parameter. + /// CallRpcPost 200 response + /// A server side error occurred. + System.Threading.Tasks.Task CallRpcPostAsync(string functionName, System.IO.Stream body = null, string? select = null, string? content_Profile = null, string? prefer = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Horizontal filters — rows matching these filters will be deleted. + /// DeleteRows 200 response + /// A server side error occurred. + System.Threading.Tasks.Task DeleteRowsAsync(string table, string? select = null, System.Collections.Generic.IDictionary? filters = null, string? content_Profile = null, string? prefer = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Column selection — comma-separated, supports aliasing, casting, embedded + ///
resources, and JSON operators. e.g. "id,name,orders(total,status)". + /// Ordering — e.g. "name.asc,age.desc.nullslast" + /// Maximum number of rows to return. + /// Row offset for pagination. + /// Horizontal filters — each entry becomes a query parameter. + ///
Key: column name (or "or"/"and" for logical groups). + ///
Value: "{operator}.{value}" e.g. {"id": "eq.5", "name": "like.foo*"}. + ///
See FilterOperator for the full list of operators. + /// Response format. e.g. "application/json" (default), "text/csv", + ///
"application/vnd.pgrst.object+json" (singular-row mode). + /// Target a non-default schema exposed by PostgREST. + /// Counting mode. e.g. "count=exact", "count=planned", "count=estimated". + /// Range-based pagination — e.g. "0-9" (ten rows starting at 0). + /// Unit for the Range header. Defaults to "items". + /// SelectRows 200 response + /// A server side error occurred. + System.Threading.Tasks.Task SelectRowsAsync(string table, string? select = null, string? order = null, double? limit = null, double? offset = null, System.Collections.Generic.IDictionary? filters = null, string? accept = null, string? accept_Profile = null, string? prefer = null, string? range = null, string? range_Unit = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Horizontal filters — rows matching these filters will be updated. + ///
Key: column name. Value: "{operator}.{value}" e.g. {"id": "eq.5"}. + /// UpdateRows 200 response + /// A server side error occurred. + System.Threading.Tasks.Task UpdateRowsAsync(System.IO.Stream body, string table, string? select = null, System.Collections.Generic.IDictionary? filters = null, string? content_Profile = null, string? prefer = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Columns to select in the returned representation (requires return=representation). + /// Restrict which columns may be populated (useful with CSV uploads). + /// Target a non-default schema for the write. + /// Return behavior and conflict handling. + ///
e.g. "return=representation", "return=minimal" (default), + ///
"return=headers-only", "resolution=merge-duplicates". + /// InsertRows 201 response + /// A server side error occurred. + System.Threading.Tasks.Task InsertRowsAsync(System.IO.Stream body, string table, string? select = null, string? columns = null, string? content_Profile = null, string? prefer = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Columns to match for conflict detection (if not the primary key). + /// Horizontal filters — rows matching these filters will be upserted. + /// e.g. "return=representation", "resolution=merge-duplicates", + ///
"resolution=ignore-duplicates". + /// UpsertRows 200 response + /// A server side error occurred. + System.Threading.Tasks.Task UpsertRowsAsync(System.IO.Stream body, string table, string? select = null, string? on_conflict = null, System.Collections.Generic.IDictionary? filters = null, string? content_Profile = null, string? prefer = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DatabaseClient : IDatabaseClient + { + private System.Net.Http.HttpClient _httpClient; + private static System.Lazy _settings = new System.Lazy(CreateSerializerSettings, true); + private System.Text.Json.JsonSerializerOptions _instanceSettings; + + #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + public DatabaseClient(System.Net.Http.HttpClient httpClient) + #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + { + _httpClient = httpClient; + Initialize(); + } + + private static System.Text.Json.JsonSerializerOptions CreateSerializerSettings() + { + var settings = new System.Text.Json.JsonSerializerOptions(); + UpdateJsonSerializerSettings(settings); + return settings; + } + + protected System.Text.Json.JsonSerializerOptions JsonSerializerSettings { get { return _instanceSettings ?? _settings.Value; } } + + static partial void UpdateJsonSerializerSettings(System.Text.Json.JsonSerializerOptions settings); + + partial void Initialize(); + + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url); + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); + partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Function arguments — each entry becomes a query parameter. + ///
Keys and value formats are defined by the PostgreSQL function signature. + /// CallRpcGet 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CallRpcGetAsync(string functionName, string? select = null, System.Collections.Generic.IDictionary? args = null, string? accept_Profile = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (functionName == null) + throw new System.ArgumentNullException("functionName"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (accept_Profile != null) + request_.Headers.TryAddWithoutValidation("Accept-Profile", ConvertToString(accept_Profile, System.Globalization.CultureInfo.InvariantCulture)); + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/octet-stream")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "rpc/{functionName}" + urlBuilder_.Append("rpc/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(functionName, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('?'); + if (select != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("select")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(select, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (args != null) + { + foreach (var item_ in args) { urlBuilder_.Append(System.Uri.EscapeDataString(item_.Key)).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(item_.Value, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); } + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200 || status_ == 206) + { + var responseStream_ = response_.Content == null ? System.IO.Stream.Null : await ReadAsStreamAsync(response_.Content, cancellationToken).ConfigureAwait(false); + var fileResponse_ = new FileResponse(status_, headers_, responseStream_, null, response_); + disposeClient_ = false; disposeResponse_ = false; // response and client are disposed by FileResponse + return fileResponse_; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("DatabaseError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// e.g. "params=single-object" — treat the entire body as a single parameter. + /// CallRpcPost 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CallRpcPostAsync(string functionName, System.IO.Stream body = null, string? select = null, string? content_Profile = null, string? prefer = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (functionName == null) + throw new System.ArgumentNullException("functionName"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (content_Profile != null) + request_.Headers.TryAddWithoutValidation("Content-Profile", ConvertToString(content_Profile, System.Globalization.CultureInfo.InvariantCulture)); + + if (prefer != null) + request_.Headers.TryAddWithoutValidation("Prefer", ConvertToString(prefer, System.Globalization.CultureInfo.InvariantCulture)); + var content_ = new System.Net.Http.StreamContent(body); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/octet-stream"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/octet-stream")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "rpc/{functionName}" + urlBuilder_.Append("rpc/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(functionName, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('?'); + if (select != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("select")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(select, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200 || status_ == 206) + { + var responseStream_ = response_.Content == null ? System.IO.Stream.Null : await ReadAsStreamAsync(response_.Content, cancellationToken).ConfigureAwait(false); + var fileResponse_ = new FileResponse(status_, headers_, responseStream_, null, response_); + disposeClient_ = false; disposeResponse_ = false; // response and client are disposed by FileResponse + return fileResponse_; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("DatabaseError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Horizontal filters — rows matching these filters will be deleted. + /// DeleteRows 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task DeleteRowsAsync(string table, string? select = null, System.Collections.Generic.IDictionary? filters = null, string? content_Profile = null, string? prefer = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (table == null) + throw new System.ArgumentNullException("table"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (content_Profile != null) + request_.Headers.TryAddWithoutValidation("Content-Profile", ConvertToString(content_Profile, System.Globalization.CultureInfo.InvariantCulture)); + + if (prefer != null) + request_.Headers.TryAddWithoutValidation("Prefer", ConvertToString(prefer, System.Globalization.CultureInfo.InvariantCulture)); + request_.Method = new System.Net.Http.HttpMethod("DELETE"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/octet-stream")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "{table}" + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(table, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('?'); + if (select != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("select")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(select, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filters != null) + { + foreach (var item_ in filters) { urlBuilder_.Append(System.Uri.EscapeDataString(item_.Key)).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(item_.Value, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); } + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200 || status_ == 206) + { + var responseStream_ = response_.Content == null ? System.IO.Stream.Null : await ReadAsStreamAsync(response_.Content, cancellationToken).ConfigureAwait(false); + var fileResponse_ = new FileResponse(status_, headers_, responseStream_, null, response_); + disposeClient_ = false; disposeResponse_ = false; // response and client are disposed by FileResponse + return fileResponse_; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("DatabaseError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Column selection — comma-separated, supports aliasing, casting, embedded + ///
resources, and JSON operators. e.g. "id,name,orders(total,status)". + /// Ordering — e.g. "name.asc,age.desc.nullslast" + /// Maximum number of rows to return. + /// Row offset for pagination. + /// Horizontal filters — each entry becomes a query parameter. + ///
Key: column name (or "or"/"and" for logical groups). + ///
Value: "{operator}.{value}" e.g. {"id": "eq.5", "name": "like.foo*"}. + ///
See FilterOperator for the full list of operators. + /// Response format. e.g. "application/json" (default), "text/csv", + ///
"application/vnd.pgrst.object+json" (singular-row mode). + /// Target a non-default schema exposed by PostgREST. + /// Counting mode. e.g. "count=exact", "count=planned", "count=estimated". + /// Range-based pagination — e.g. "0-9" (ten rows starting at 0). + /// Unit for the Range header. Defaults to "items". + /// SelectRows 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SelectRowsAsync(string table, string? select = null, string? order = null, double? limit = null, double? offset = null, System.Collections.Generic.IDictionary? filters = null, string? accept = null, string? accept_Profile = null, string? prefer = null, string? range = null, string? range_Unit = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (table == null) + throw new System.ArgumentNullException("table"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (accept != null) + request_.Headers.TryAddWithoutValidation("Accept", ConvertToString(accept, System.Globalization.CultureInfo.InvariantCulture)); + + if (accept_Profile != null) + request_.Headers.TryAddWithoutValidation("Accept-Profile", ConvertToString(accept_Profile, System.Globalization.CultureInfo.InvariantCulture)); + + if (prefer != null) + request_.Headers.TryAddWithoutValidation("Prefer", ConvertToString(prefer, System.Globalization.CultureInfo.InvariantCulture)); + + if (range != null) + request_.Headers.TryAddWithoutValidation("Range", ConvertToString(range, System.Globalization.CultureInfo.InvariantCulture)); + + if (range_Unit != null) + request_.Headers.TryAddWithoutValidation("Range-Unit", ConvertToString(range_Unit, System.Globalization.CultureInfo.InvariantCulture)); + request_.Method = new System.Net.Http.HttpMethod("GET"); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "{table}" + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(table, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('?'); + if (select != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("select")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(select, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (order != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("order")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(order, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (offset != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("offset")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(offset, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filters != null) + { + foreach (var item_ in filters) { urlBuilder_.Append(System.Uri.EscapeDataString(item_.Key)).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(item_.Value, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); } + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200 || status_ == 206) + { + var responseStream_ = response_.Content == null ? System.IO.Stream.Null : await ReadAsStreamAsync(response_.Content, cancellationToken).ConfigureAwait(false); + var fileResponse_ = new FileResponse(status_, headers_, responseStream_, null, response_); + disposeClient_ = false; disposeResponse_ = false; // response and client are disposed by FileResponse + return fileResponse_; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("DatabaseError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Horizontal filters — rows matching these filters will be updated. + ///
Key: column name. Value: "{operator}.{value}" e.g. {"id": "eq.5"}. + /// UpdateRows 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task UpdateRowsAsync(System.IO.Stream body, string table, string? select = null, System.Collections.Generic.IDictionary? filters = null, string? content_Profile = null, string? prefer = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (table == null) + throw new System.ArgumentNullException("table"); + + if (body == null) + throw new System.ArgumentNullException("body"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (content_Profile != null) + request_.Headers.TryAddWithoutValidation("Content-Profile", ConvertToString(content_Profile, System.Globalization.CultureInfo.InvariantCulture)); + + if (prefer != null) + request_.Headers.TryAddWithoutValidation("Prefer", ConvertToString(prefer, System.Globalization.CultureInfo.InvariantCulture)); + var content_ = new System.Net.Http.StreamContent(body); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/octet-stream"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("PATCH"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/octet-stream")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "{table}" + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(table, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('?'); + if (select != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("select")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(select, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filters != null) + { + foreach (var item_ in filters) { urlBuilder_.Append(System.Uri.EscapeDataString(item_.Key)).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(item_.Value, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); } + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200 || status_ == 206) + { + var responseStream_ = response_.Content == null ? System.IO.Stream.Null : await ReadAsStreamAsync(response_.Content, cancellationToken).ConfigureAwait(false); + var fileResponse_ = new FileResponse(status_, headers_, responseStream_, null, response_); + disposeClient_ = false; disposeResponse_ = false; // response and client are disposed by FileResponse + return fileResponse_; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("DatabaseError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Columns to select in the returned representation (requires return=representation). + /// Restrict which columns may be populated (useful with CSV uploads). + /// Target a non-default schema for the write. + /// Return behavior and conflict handling. + ///
e.g. "return=representation", "return=minimal" (default), + ///
"return=headers-only", "resolution=merge-duplicates". + /// InsertRows 201 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task InsertRowsAsync(System.IO.Stream body, string table, string? select = null, string? columns = null, string? content_Profile = null, string? prefer = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (table == null) + throw new System.ArgumentNullException("table"); + + if (body == null) + throw new System.ArgumentNullException("body"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (content_Profile != null) + request_.Headers.TryAddWithoutValidation("Content-Profile", ConvertToString(content_Profile, System.Globalization.CultureInfo.InvariantCulture)); + + if (prefer != null) + request_.Headers.TryAddWithoutValidation("Prefer", ConvertToString(prefer, System.Globalization.CultureInfo.InvariantCulture)); + var content_ = new System.Net.Http.StreamContent(body); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/octet-stream"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/octet-stream")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "{table}" + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(table, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('?'); + if (select != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("select")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(select, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (columns != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("columns")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(columns, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 201) + { + var responseStream_ = response_.Content == null ? System.IO.Stream.Null : await ReadAsStreamAsync(response_.Content, cancellationToken).ConfigureAwait(false); + var fileResponse_ = new FileResponse(status_, headers_, responseStream_, null, response_); + disposeClient_ = false; disposeResponse_ = false; // response and client are disposed by FileResponse + return fileResponse_; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("DatabaseError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Columns to match for conflict detection (if not the primary key). + /// Horizontal filters — rows matching these filters will be upserted. + /// e.g. "return=representation", "resolution=merge-duplicates", + ///
"resolution=ignore-duplicates". + /// UpsertRows 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task UpsertRowsAsync(System.IO.Stream body, string table, string? select = null, string? on_conflict = null, System.Collections.Generic.IDictionary? filters = null, string? content_Profile = null, string? prefer = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (table == null) + throw new System.ArgumentNullException("table"); + + if (body == null) + throw new System.ArgumentNullException("body"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (content_Profile != null) + request_.Headers.TryAddWithoutValidation("Content-Profile", ConvertToString(content_Profile, System.Globalization.CultureInfo.InvariantCulture)); + + if (prefer != null) + request_.Headers.TryAddWithoutValidation("Prefer", ConvertToString(prefer, System.Globalization.CultureInfo.InvariantCulture)); + var content_ = new System.Net.Http.StreamContent(body); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/octet-stream"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("PUT"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/octet-stream")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "{table}" + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(table, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('?'); + if (select != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("select")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(select, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (on_conflict != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("on_conflict")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(on_conflict, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filters != null) + { + foreach (var item_ in filters) { urlBuilder_.Append(System.Uri.EscapeDataString(item_.Key)).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(item_.Value, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); } + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200 || status_ == 206) + { + var responseStream_ = response_.Content == null ? System.IO.Stream.Null : await ReadAsStreamAsync(response_.Content, cancellationToken).ConfigureAwait(false); + var fileResponse_ = new FileResponse(status_, headers_, responseStream_, null, response_); + disposeClient_ = false; disposeResponse_ = false; // response and client are disposed by FileResponse + return fileResponse_; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("DatabaseError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + protected struct ObjectResponseResult + { + public ObjectResponseResult(T responseObject, string responseText) + { + this.Object = responseObject; + this.Text = responseText; + } + + public T Object { get; } + + public string Text { get; } + } + + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + private static System.Threading.Tasks.Task ReadAsStringAsync(System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) + { + #if NET5_0_OR_GREATER + return content.ReadAsStringAsync(cancellationToken); + #else + return content.ReadAsStringAsync(); + #endif + } + + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + private static System.Threading.Tasks.Task ReadAsStreamAsync(System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) + { + #if NET5_0_OR_GREATER + return content.ReadAsStreamAsync(cancellationToken); + #else + return content.ReadAsStreamAsync(); + #endif + } + + public bool ReadResponseAsString { get; set; } + + protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) + { + if (response == null || response.Content == null) + { + return new ObjectResponseResult(default(T)!, string.Empty); + } + + if (ReadResponseAsString) + { + var responseText = await ReadAsStringAsync(response.Content, cancellationToken).ConfigureAwait(false); + try + { + var typedBody = System.Text.Json.JsonSerializer.Deserialize(responseText, JsonSerializerSettings); + return new ObjectResponseResult(typedBody!, responseText); + } + catch (System.Text.Json.JsonException exception) + { + var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception); + } + } + else + { + try + { + using (var responseStream = await ReadAsStreamAsync(response.Content, cancellationToken).ConfigureAwait(false)) + { + var typedBody = await System.Text.Json.JsonSerializer.DeserializeAsync(responseStream, JsonSerializerSettings, cancellationToken).ConfigureAwait(false); + return new ObjectResponseResult(typedBody!, string.Empty); + } + } + catch (System.Text.Json.JsonException exception) + { + var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception); + } + } + } + + private string ConvertToString(object? value, System.Globalization.CultureInfo cultureInfo) + { + if (value == null) + { + return ""; + } + + if (value is System.Enum) + { + var name = System.Enum.GetName(value.GetType(), value); + if (name != null) + { + var field_ = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); + if (field_ != null) + { + var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field_, typeof(System.Runtime.Serialization.EnumMemberAttribute)) + as System.Runtime.Serialization.EnumMemberAttribute; + if (attribute != null) + { + return attribute.Value != null ? attribute.Value : name; + } + } + + var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); + return converted == null ? string.Empty : converted; + } + } + else if (value is bool) + { + return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); + } + else if (value is byte[]) + { + return System.Convert.ToBase64String((byte[]) value); + } + else if (value is string[]) + { + return string.Join(",", (string[])value); + } + else if (value.GetType().IsArray) + { + var valueArray = (System.Array)value; + var valueTextArray = new string[valueArray.Length]; + for (var i = 0; i < valueArray.Length; i++) + { + valueTextArray[i] = ConvertToString(valueArray.GetValue(i), cultureInfo); + } + return string.Join(",", valueTextArray); + } + + var result = System.Convert.ToString(value, cultureInfo); + return result == null ? "" : result; + } + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DatabaseErrorResponseContent + { + + /// + /// PostgreSQL error code (e.g. "23505") or PostgREST error code (e.g. "PGRST301"). + /// + [System.Text.Json.Serialization.JsonPropertyName("code")] + public string Code { get; set; } = default!; + + /// + /// Human-readable error message. + /// + [System.Text.Json.Serialization.JsonPropertyName("message")] + public string Message { get; set; } = default!; + + /// + /// Extra context — constraint name, offending column, etc. + /// + [System.Text.Json.Serialization.JsonPropertyName("details")] + public string Details { get; set; } = default!; + + /// + /// Hint from PostgreSQL. + /// + [System.Text.Json.Serialization.JsonPropertyName("hint")] + public string Hint { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Generic string-to-string map — used for arbitrary query parameter collections + ///
(e.g. PostgREST filter params, RPC GET arguments). + ///
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class StringMap : System.Collections.Generic.Dictionary + { + + } + + /// + /// PostgREST column filter operators. Format a filter value as "{operator}.{value}", e.g. "eq.5". Prefix with "not." to negate: "not.eq.5". For logical grouping use keys "or" / "and" in the filters map. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public enum FilterOperator + { + + [System.Runtime.Serialization.EnumMember(Value = @"eq")] + Eq = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"neq")] + Neq = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"lt")] + Lt = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"lte")] + Lte = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"gt")] + Gt = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"gte")] + Gte = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"like")] + Like = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"ilike")] + Ilike = 7, + + [System.Runtime.Serialization.EnumMember(Value = @"match")] + Match = 8, + + [System.Runtime.Serialization.EnumMember(Value = @"imatch")] + Imatch = 9, + + [System.Runtime.Serialization.EnumMember(Value = @"is")] + Is = 10, + + [System.Runtime.Serialization.EnumMember(Value = @"isdistinct")] + Isdistinct = 11, + + [System.Runtime.Serialization.EnumMember(Value = @"in")] + In = 12, + + [System.Runtime.Serialization.EnumMember(Value = @"cs")] + Cs = 13, + + [System.Runtime.Serialization.EnumMember(Value = @"cd")] + Cd = 14, + + [System.Runtime.Serialization.EnumMember(Value = @"ov")] + Ov = 15, + + [System.Runtime.Serialization.EnumMember(Value = @"sl")] + Sl = 16, + + [System.Runtime.Serialization.EnumMember(Value = @"sr")] + Sr = 17, + + [System.Runtime.Serialization.EnumMember(Value = @"nxl")] + Nxl = 18, + + [System.Runtime.Serialization.EnumMember(Value = @"nxr")] + Nxr = 19, + + [System.Runtime.Serialization.EnumMember(Value = @"adj")] + Adj = 20, + + [System.Runtime.Serialization.EnumMember(Value = @"fts")] + Fts = 21, + + [System.Runtime.Serialization.EnumMember(Value = @"plfts")] + Plfts = 22, + + [System.Runtime.Serialization.EnumMember(Value = @"phfts")] + Phfts = 23, + + [System.Runtime.Serialization.EnumMember(Value = @"wfts")] + Wfts = 24, + + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class FileParameter + { + public FileParameter(System.IO.Stream data) + : this (data, null, null) + { + } + + public FileParameter(System.IO.Stream data, string? fileName) + : this (data, fileName, null) + { + } + + public FileParameter(System.IO.Stream data, string? fileName, string? contentType) + { + Data = data; + FileName = fileName; + ContentType = contentType; + } + + public System.IO.Stream Data { get; private set; } + + public string? FileName { get; private set; } + + public string? ContentType { get; private set; } + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class FileResponse : System.IDisposable + { + private System.IDisposable? _client; + private System.IDisposable? _response; + + public int StatusCode { get; private set; } + + public System.Collections.Generic.IReadOnlyDictionary> Headers { get; private set; } + + public System.IO.Stream Stream { get; private set; } + + public bool IsPartial + { + get { return StatusCode == 206; } + } + + public FileResponse(int statusCode, System.Collections.Generic.IReadOnlyDictionary> headers, System.IO.Stream stream, System.IDisposable? client, System.IDisposable? response) + { + StatusCode = statusCode; + Headers = headers; + Stream = stream; + _client = client; + _response = response; + } + + public void Dispose() + { + Stream.Dispose(); + if (_response != null) + _response.Dispose(); + if (_client != null) + _client.Dispose(); + } + } + + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ApiException : System.Exception + { + public int StatusCode { get; private set; } + + public string? Response { get; private set; } + + public System.Collections.Generic.IReadOnlyDictionary> Headers { get; private set; } + + public ApiException(string message, int statusCode, string? response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Exception? innerException) + : base(message + "\n\nStatus: " + statusCode + "\nResponse: \n" + ((response == null) ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException) + { + StatusCode = statusCode; + Response = response; + Headers = headers; + } + + public override string ToString() + { + return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString()); + } + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ApiException : ApiException + { + public TResult Result { get; private set; } + + public ApiException(string message, int statusCode, string? response, System.Collections.Generic.IReadOnlyDictionary> headers, TResult result, System.Exception? innerException) + : base(message, statusCode, response, headers, innerException) + { + Result = result; + } + } + +} + +#pragma warning restore 108 +#pragma warning restore 114 +#pragma warning restore 472 +#pragma warning restore 612 +#pragma warning restore 649 +#pragma warning restore 1573 +#pragma warning restore 1591 +#pragma warning restore 8073 +#pragma warning restore 3016 +#pragma warning restore 8600 +#pragma warning restore 8602 +#pragma warning restore 8603 +#pragma warning restore 8604 +#pragma warning restore 8625 +#pragma warning restore 8765 \ No newline at end of file diff --git a/nswag-spike/generated/DatabaseService.ready.json b/nswag-spike/generated/DatabaseService.ready.json new file mode 100644 index 00000000..470204f7 --- /dev/null +++ b/nswag-spike/generated/DatabaseService.ready.json @@ -0,0 +1,704 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Supabase Database API", + "version": "1.0", + "description": "PostgREST-backed database API.\n\nBase URL: https://{project-ref}.supabase.co/rest/v1\n\nKnown limitations:\n 1. Write operations return 204 (no body) by default and 200 with a body when\n Prefer: return=representation \u2014 the model uses 200 throughout so generators\n always produce body-parsing code; clients must tolerate empty bodies.\n 2. RPC GET arguments are function-specific; they are expressed via the same\n @httpQueryParams map as row filters, with function-defined keys." + }, + "paths": { + "/rpc/{functionName}": { + "get": { + "operationId": "CallRpcGet", + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "args", + "in": "query", + "description": "Function arguments \u2014 each entry becomes a query parameter.\nKeys and value formats are defined by the PostgreSQL function signature.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Accept-Profile", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "CallRpcGet 200 response", + "headers": { + "Content-Range": { + "schema": { + "type": "string" + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "post": { + "operationId": "CallRpcPost", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "Content-Profile", + "in": "header", + "schema": { + "type": "string" + } + }, + { + "name": "Prefer", + "in": "header", + "description": "e.g. \"params=single-object\" \u2014 treat the entire body as a single parameter.", + "schema": { + "type": "string", + "description": "e.g. \"params=single-object\" \u2014 treat the entire body as a single parameter." + } + } + ], + "responses": { + "200": { + "description": "CallRpcPost 200 response", + "headers": { + "Content-Range": { + "schema": { + "type": "string" + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + } + }, + "/{table}": { + "delete": { + "operationId": "DeleteRows", + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "filters", + "in": "query", + "description": "Horizontal filters \u2014 rows matching these filters will be deleted.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Content-Profile", + "in": "header", + "schema": { + "type": "string" + } + }, + { + "name": "Prefer", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "DeleteRows 200 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "get": { + "operationId": "SelectRows", + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "description": "Column selection \u2014 comma-separated, supports aliasing, casting, embedded\nresources, and JSON operators. e.g. \"id,name,orders(total,status)\".", + "schema": { + "type": "string", + "description": "Column selection \u2014 comma-separated, supports aliasing, casting, embedded\nresources, and JSON operators. e.g. \"id,name,orders(total,status)\"." + } + }, + { + "name": "order", + "in": "query", + "description": "Ordering \u2014 e.g. \"name.asc,age.desc.nullslast\"", + "schema": { + "type": "string", + "description": "Ordering \u2014 e.g. \"name.asc,age.desc.nullslast\"" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of rows to return.", + "schema": { + "type": "number", + "description": "Maximum number of rows to return." + } + }, + { + "name": "offset", + "in": "query", + "description": "Row offset for pagination.", + "schema": { + "type": "number", + "description": "Row offset for pagination." + } + }, + { + "name": "filters", + "in": "query", + "description": "Horizontal filters \u2014 each entry becomes a query parameter.\nKey: column name (or \"or\"/\"and\" for logical groups).\nValue: \"{operator}.{value}\" e.g. {\"id\": \"eq.5\", \"name\": \"like.foo*\"}.\nSee FilterOperator for the full list of operators.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Accept", + "in": "header", + "description": "Response format. e.g. \"application/json\" (default), \"text/csv\",\n\"application/vnd.pgrst.object+json\" (singular-row mode).", + "schema": { + "type": "string", + "description": "Response format. e.g. \"application/json\" (default), \"text/csv\",\n\"application/vnd.pgrst.object+json\" (singular-row mode)." + } + }, + { + "name": "Accept-Profile", + "in": "header", + "description": "Target a non-default schema exposed by PostgREST.", + "schema": { + "type": "string", + "description": "Target a non-default schema exposed by PostgREST." + } + }, + { + "name": "Prefer", + "in": "header", + "description": "Counting mode. e.g. \"count=exact\", \"count=planned\", \"count=estimated\".", + "schema": { + "type": "string", + "description": "Counting mode. e.g. \"count=exact\", \"count=planned\", \"count=estimated\"." + } + }, + { + "name": "Range", + "in": "header", + "description": "Range-based pagination \u2014 e.g. \"0-9\" (ten rows starting at 0).", + "schema": { + "type": "string", + "description": "Range-based pagination \u2014 e.g. \"0-9\" (ten rows starting at 0)." + } + }, + { + "name": "Range-Unit", + "in": "header", + "description": "Unit for the Range header. Defaults to \"items\".", + "schema": { + "type": "string", + "description": "Unit for the Range header. Defaults to \"items\"." + } + } + ], + "responses": { + "200": { + "description": "SelectRows 200 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "patch": { + "operationId": "UpdateRows", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "filters", + "in": "query", + "description": "Horizontal filters \u2014 rows matching these filters will be updated.\nKey: column name. Value: \"{operator}.{value}\" e.g. {\"id\": \"eq.5\"}.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Content-Profile", + "in": "header", + "schema": { + "type": "string" + } + }, + { + "name": "Prefer", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "UpdateRows 200 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "post": { + "operationId": "InsertRows", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "description": "Columns to select in the returned representation (requires return=representation).", + "schema": { + "type": "string", + "description": "Columns to select in the returned representation (requires return=representation)." + } + }, + { + "name": "columns", + "in": "query", + "description": "Restrict which columns may be populated (useful with CSV uploads).", + "schema": { + "type": "string", + "description": "Restrict which columns may be populated (useful with CSV uploads)." + } + }, + { + "name": "Content-Profile", + "in": "header", + "description": "Target a non-default schema for the write.", + "schema": { + "type": "string", + "description": "Target a non-default schema for the write." + } + }, + { + "name": "Prefer", + "in": "header", + "description": "Return behavior and conflict handling.\ne.g. \"return=representation\", \"return=minimal\" (default),\n \"return=headers-only\", \"resolution=merge-duplicates\".", + "schema": { + "type": "string", + "description": "Return behavior and conflict handling.\ne.g. \"return=representation\", \"return=minimal\" (default),\n \"return=headers-only\", \"resolution=merge-duplicates\"." + } + } + ], + "responses": { + "201": { + "description": "InsertRows 201 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "put": { + "operationId": "UpsertRows", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "on_conflict", + "in": "query", + "description": "Columns to match for conflict detection (if not the primary key).", + "schema": { + "type": "string", + "description": "Columns to match for conflict detection (if not the primary key)." + } + }, + { + "name": "filters", + "in": "query", + "description": "Horizontal filters \u2014 rows matching these filters will be upserted.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Content-Profile", + "in": "header", + "schema": { + "type": "string" + } + }, + { + "name": "Prefer", + "in": "header", + "description": "e.g. \"return=representation\", \"resolution=merge-duplicates\",\n \"resolution=ignore-duplicates\".", + "schema": { + "type": "string", + "description": "e.g. \"return=representation\", \"resolution=merge-duplicates\",\n \"resolution=ignore-duplicates\"." + } + } + ], + "responses": { + "200": { + "description": "UpsertRows 200 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "DatabaseErrorResponseContent": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "PostgreSQL error code (e.g. \"23505\") or PostgREST error code (e.g. \"PGRST301\")." + }, + "message": { + "type": "string", + "description": "Human-readable error message." + }, + "details": { + "type": "string", + "description": "Extra context \u2014 constraint name, offending column, etc." + }, + "hint": { + "type": "string", + "description": "Hint from PostgreSQL." + } + } + }, + "StringMap": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Generic string-to-string map \u2014 used for arbitrary query parameter collections\n(e.g. PostgREST filter params, RPC GET arguments)." + }, + "FilterOperator": { + "type": "string", + "description": "PostgREST column filter operators. Format a filter value as \"{operator}.{value}\", e.g. \"eq.5\". Prefix with \"not.\" to negate: \"not.eq.5\". For logical grouping use keys \"or\" / \"and\" in the filters map.", + "enum": [ + "eq", + "neq", + "lt", + "lte", + "gt", + "gte", + "like", + "ilike", + "match", + "imatch", + "is", + "isdistinct", + "in", + "cs", + "cd", + "ov", + "sl", + "sr", + "nxl", + "nxr", + "adj", + "fts", + "plfts", + "phfts", + "wfts" + ] + } + } + } +} \ No newline at end of file diff --git a/nswag-spike/generated/FunctionsClient.cs b/nswag-spike/generated/FunctionsClient.cs new file mode 100644 index 00000000..323f77b7 --- /dev/null +++ b/nswag-spike/generated/FunctionsClient.cs @@ -0,0 +1,856 @@ +//---------------------- +// +// Generated using the NSwag toolchain v14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) +// +//---------------------- + +#nullable enable + +#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended." +#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." +#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' +#pragma warning disable 612 // Disable "CS0612 '...' is obsolete" +#pragma warning disable 649 // Disable "CS0649 Field is never assigned to, and will always have its default value null" +#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... +#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." +#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'" +#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant" +#pragma warning disable 8600 // Disable "CS8600 Converting null literal or possible null value to non-nullable type" +#pragma warning disable 8602 // Disable "CS8602 Dereference of a possibly null reference" +#pragma warning disable 8603 // Disable "CS8603 Possible null reference return" +#pragma warning disable 8604 // Disable "CS8604 Possible null reference argument for parameter" +#pragma warning disable 8625 // Disable "CS8625 Cannot convert null literal to non-nullable reference type" +#pragma warning disable 8765 // Disable "CS8765 Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes)." + +namespace Supabase.Functions.Gen +{ + using System = global::System; + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial interface IFunctionsClient + { + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Arbitrary query parameters appended to the function URL. + ///
Corresponds to FunctionInvokeOptions.query. + /// InvokeFunctionDelete 200 response + /// A server side error occurred. + System.Threading.Tasks.Task InvokeFunctionDeleteAsync(string functionName, System.IO.Stream body = null, System.Collections.Generic.IDictionary? query = null, string? x_region = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Arbitrary query parameters appended to the function URL. + ///
Corresponds to FunctionInvokeOptions.query. + /// InvokeFunctionGet 200 response + /// A server side error occurred. + System.Threading.Tasks.Task InvokeFunctionGetAsync(string functionName, System.Collections.Generic.IDictionary? query = null, string? x_region = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Arbitrary query parameters appended to the function URL. + ///
Corresponds to FunctionInvokeOptions.query. + /// InvokeFunctionPatch 200 response + /// A server side error occurred. + System.Threading.Tasks.Task InvokeFunctionPatchAsync(string functionName, System.IO.Stream body = null, System.Collections.Generic.IDictionary? query = null, string? x_region = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Arbitrary query parameters appended to the function URL. + ///
Corresponds to FunctionInvokeOptions.query. + /// InvokeFunctionPost 200 response + /// A server side error occurred. + System.Threading.Tasks.Task InvokeFunctionPostAsync(string functionName, System.IO.Stream body = null, System.Collections.Generic.IDictionary? query = null, string? x_region = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Arbitrary query parameters appended to the function URL. + ///
Corresponds to FunctionInvokeOptions.query. + /// InvokeFunctionPut 200 response + /// A server side error occurred. + System.Threading.Tasks.Task InvokeFunctionPutAsync(string functionName, System.IO.Stream body = null, System.Collections.Generic.IDictionary? query = null, string? x_region = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class FunctionsClient : IFunctionsClient + { + private System.Net.Http.HttpClient _httpClient; + private static System.Lazy _settings = new System.Lazy(CreateSerializerSettings, true); + private System.Text.Json.JsonSerializerOptions _instanceSettings; + + #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + public FunctionsClient(System.Net.Http.HttpClient httpClient) + #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + { + _httpClient = httpClient; + Initialize(); + } + + private static System.Text.Json.JsonSerializerOptions CreateSerializerSettings() + { + var settings = new System.Text.Json.JsonSerializerOptions(); + UpdateJsonSerializerSettings(settings); + return settings; + } + + protected System.Text.Json.JsonSerializerOptions JsonSerializerSettings { get { return _instanceSettings ?? _settings.Value; } } + + static partial void UpdateJsonSerializerSettings(System.Text.Json.JsonSerializerOptions settings); + + partial void Initialize(); + + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url); + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); + partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Arbitrary query parameters appended to the function URL. + ///
Corresponds to FunctionInvokeOptions.query. + /// InvokeFunctionDelete 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task InvokeFunctionDeleteAsync(string functionName, System.IO.Stream body = null, System.Collections.Generic.IDictionary? query = null, string? x_region = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (functionName == null) + throw new System.ArgumentNullException("functionName"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (x_region != null) + request_.Headers.TryAddWithoutValidation("x-region", ConvertToString(x_region, System.Globalization.CultureInfo.InvariantCulture)); + var content_ = new System.Net.Http.StreamContent(body); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/octet-stream"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("DELETE"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/octet-stream")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "functions/v1/{functionName}" + urlBuilder_.Append("functions/v1/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(functionName, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('?'); + if (query != null) + { + foreach (var item_ in query) { urlBuilder_.Append(System.Uri.EscapeDataString(item_.Key)).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(item_.Value, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); } + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200 || status_ == 206) + { + var responseStream_ = response_.Content == null ? System.IO.Stream.Null : await ReadAsStreamAsync(response_.Content, cancellationToken).ConfigureAwait(false); + var fileResponse_ = new FileResponse(status_, headers_, responseStream_, null, response_); + disposeClient_ = false; disposeResponse_ = false; // response and client are disposed by FileResponse + return fileResponse_; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("FunctionsError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Arbitrary query parameters appended to the function URL. + ///
Corresponds to FunctionInvokeOptions.query. + /// InvokeFunctionGet 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task InvokeFunctionGetAsync(string functionName, System.Collections.Generic.IDictionary? query = null, string? x_region = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (functionName == null) + throw new System.ArgumentNullException("functionName"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (x_region != null) + request_.Headers.TryAddWithoutValidation("x-region", ConvertToString(x_region, System.Globalization.CultureInfo.InvariantCulture)); + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/octet-stream")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "functions/v1/{functionName}" + urlBuilder_.Append("functions/v1/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(functionName, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('?'); + if (query != null) + { + foreach (var item_ in query) { urlBuilder_.Append(System.Uri.EscapeDataString(item_.Key)).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(item_.Value, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); } + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200 || status_ == 206) + { + var responseStream_ = response_.Content == null ? System.IO.Stream.Null : await ReadAsStreamAsync(response_.Content, cancellationToken).ConfigureAwait(false); + var fileResponse_ = new FileResponse(status_, headers_, responseStream_, null, response_); + disposeClient_ = false; disposeResponse_ = false; // response and client are disposed by FileResponse + return fileResponse_; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("FunctionsError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Arbitrary query parameters appended to the function URL. + ///
Corresponds to FunctionInvokeOptions.query. + /// InvokeFunctionPatch 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task InvokeFunctionPatchAsync(string functionName, System.IO.Stream body = null, System.Collections.Generic.IDictionary? query = null, string? x_region = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (functionName == null) + throw new System.ArgumentNullException("functionName"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (x_region != null) + request_.Headers.TryAddWithoutValidation("x-region", ConvertToString(x_region, System.Globalization.CultureInfo.InvariantCulture)); + var content_ = new System.Net.Http.StreamContent(body); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/octet-stream"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("PATCH"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/octet-stream")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "functions/v1/{functionName}" + urlBuilder_.Append("functions/v1/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(functionName, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('?'); + if (query != null) + { + foreach (var item_ in query) { urlBuilder_.Append(System.Uri.EscapeDataString(item_.Key)).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(item_.Value, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); } + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200 || status_ == 206) + { + var responseStream_ = response_.Content == null ? System.IO.Stream.Null : await ReadAsStreamAsync(response_.Content, cancellationToken).ConfigureAwait(false); + var fileResponse_ = new FileResponse(status_, headers_, responseStream_, null, response_); + disposeClient_ = false; disposeResponse_ = false; // response and client are disposed by FileResponse + return fileResponse_; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("FunctionsError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Arbitrary query parameters appended to the function URL. + ///
Corresponds to FunctionInvokeOptions.query. + /// InvokeFunctionPost 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task InvokeFunctionPostAsync(string functionName, System.IO.Stream body = null, System.Collections.Generic.IDictionary? query = null, string? x_region = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (functionName == null) + throw new System.ArgumentNullException("functionName"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (x_region != null) + request_.Headers.TryAddWithoutValidation("x-region", ConvertToString(x_region, System.Globalization.CultureInfo.InvariantCulture)); + var content_ = new System.Net.Http.StreamContent(body); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/octet-stream"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/octet-stream")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "functions/v1/{functionName}" + urlBuilder_.Append("functions/v1/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(functionName, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('?'); + if (query != null) + { + foreach (var item_ in query) { urlBuilder_.Append(System.Uri.EscapeDataString(item_.Key)).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(item_.Value, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); } + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200 || status_ == 206) + { + var responseStream_ = response_.Content == null ? System.IO.Stream.Null : await ReadAsStreamAsync(response_.Content, cancellationToken).ConfigureAwait(false); + var fileResponse_ = new FileResponse(status_, headers_, responseStream_, null, response_); + disposeClient_ = false; disposeResponse_ = false; // response and client are disposed by FileResponse + return fileResponse_; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("FunctionsError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Arbitrary query parameters appended to the function URL. + ///
Corresponds to FunctionInvokeOptions.query. + /// InvokeFunctionPut 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task InvokeFunctionPutAsync(string functionName, System.IO.Stream body = null, System.Collections.Generic.IDictionary? query = null, string? x_region = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (functionName == null) + throw new System.ArgumentNullException("functionName"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (x_region != null) + request_.Headers.TryAddWithoutValidation("x-region", ConvertToString(x_region, System.Globalization.CultureInfo.InvariantCulture)); + var content_ = new System.Net.Http.StreamContent(body); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/octet-stream"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("PUT"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/octet-stream")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "functions/v1/{functionName}" + urlBuilder_.Append("functions/v1/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(functionName, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('?'); + if (query != null) + { + foreach (var item_ in query) { urlBuilder_.Append(System.Uri.EscapeDataString(item_.Key)).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(item_.Value, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); } + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200 || status_ == 206) + { + var responseStream_ = response_.Content == null ? System.IO.Stream.Null : await ReadAsStreamAsync(response_.Content, cancellationToken).ConfigureAwait(false); + var fileResponse_ = new FileResponse(status_, headers_, responseStream_, null, response_); + disposeClient_ = false; disposeResponse_ = false; // response and client are disposed by FileResponse + return fileResponse_; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("FunctionsError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + protected struct ObjectResponseResult + { + public ObjectResponseResult(T responseObject, string responseText) + { + this.Object = responseObject; + this.Text = responseText; + } + + public T Object { get; } + + public string Text { get; } + } + + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + private static System.Threading.Tasks.Task ReadAsStringAsync(System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) + { + #if NET5_0_OR_GREATER + return content.ReadAsStringAsync(cancellationToken); + #else + return content.ReadAsStringAsync(); + #endif + } + + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + private static System.Threading.Tasks.Task ReadAsStreamAsync(System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) + { + #if NET5_0_OR_GREATER + return content.ReadAsStreamAsync(cancellationToken); + #else + return content.ReadAsStreamAsync(); + #endif + } + + public bool ReadResponseAsString { get; set; } + + protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) + { + if (response == null || response.Content == null) + { + return new ObjectResponseResult(default(T)!, string.Empty); + } + + if (ReadResponseAsString) + { + var responseText = await ReadAsStringAsync(response.Content, cancellationToken).ConfigureAwait(false); + try + { + var typedBody = System.Text.Json.JsonSerializer.Deserialize(responseText, JsonSerializerSettings); + return new ObjectResponseResult(typedBody!, responseText); + } + catch (System.Text.Json.JsonException exception) + { + var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception); + } + } + else + { + try + { + using (var responseStream = await ReadAsStreamAsync(response.Content, cancellationToken).ConfigureAwait(false)) + { + var typedBody = await System.Text.Json.JsonSerializer.DeserializeAsync(responseStream, JsonSerializerSettings, cancellationToken).ConfigureAwait(false); + return new ObjectResponseResult(typedBody!, string.Empty); + } + } + catch (System.Text.Json.JsonException exception) + { + var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception); + } + } + } + + private string ConvertToString(object? value, System.Globalization.CultureInfo cultureInfo) + { + if (value == null) + { + return ""; + } + + if (value is System.Enum) + { + var name = System.Enum.GetName(value.GetType(), value); + if (name != null) + { + var field_ = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); + if (field_ != null) + { + var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field_, typeof(System.Runtime.Serialization.EnumMemberAttribute)) + as System.Runtime.Serialization.EnumMemberAttribute; + if (attribute != null) + { + return attribute.Value != null ? attribute.Value : name; + } + } + + var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); + return converted == null ? string.Empty : converted; + } + } + else if (value is bool) + { + return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); + } + else if (value is byte[]) + { + return System.Convert.ToBase64String((byte[]) value); + } + else if (value is string[]) + { + return string.Join(",", (string[])value); + } + else if (value.GetType().IsArray) + { + var valueArray = (System.Array)value; + var valueTextArray = new string[valueArray.Length]; + for (var i = 0; i < valueArray.Length; i++) + { + valueTextArray[i] = ConvertToString(valueArray.GetValue(i), cultureInfo); + } + return string.Join(",", valueTextArray); + } + + var result = System.Convert.ToString(value, cultureInfo); + return result == null ? "" : result; + } + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class FunctionsErrorResponseContent + { + + [System.Text.Json.Serialization.JsonPropertyName("message")] + public string Message { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Generic string-to-string map — used for arbitrary query parameter collections + ///
(e.g. PostgREST filter params, RPC GET arguments). + ///
+ [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class StringMap : System.Collections.Generic.Dictionary + { + + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class FileParameter + { + public FileParameter(System.IO.Stream data) + : this (data, null, null) + { + } + + public FileParameter(System.IO.Stream data, string? fileName) + : this (data, fileName, null) + { + } + + public FileParameter(System.IO.Stream data, string? fileName, string? contentType) + { + Data = data; + FileName = fileName; + ContentType = contentType; + } + + public System.IO.Stream Data { get; private set; } + + public string? FileName { get; private set; } + + public string? ContentType { get; private set; } + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class FileResponse : System.IDisposable + { + private System.IDisposable? _client; + private System.IDisposable? _response; + + public int StatusCode { get; private set; } + + public System.Collections.Generic.IReadOnlyDictionary> Headers { get; private set; } + + public System.IO.Stream Stream { get; private set; } + + public bool IsPartial + { + get { return StatusCode == 206; } + } + + public FileResponse(int statusCode, System.Collections.Generic.IReadOnlyDictionary> headers, System.IO.Stream stream, System.IDisposable? client, System.IDisposable? response) + { + StatusCode = statusCode; + Headers = headers; + Stream = stream; + _client = client; + _response = response; + } + + public void Dispose() + { + Stream.Dispose(); + if (_response != null) + _response.Dispose(); + if (_client != null) + _client.Dispose(); + } + } + + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ApiException : System.Exception + { + public int StatusCode { get; private set; } + + public string? Response { get; private set; } + + public System.Collections.Generic.IReadOnlyDictionary> Headers { get; private set; } + + public ApiException(string message, int statusCode, string? response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Exception? innerException) + : base(message + "\n\nStatus: " + statusCode + "\nResponse: \n" + ((response == null) ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException) + { + StatusCode = statusCode; + Response = response; + Headers = headers; + } + + public override string ToString() + { + return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString()); + } + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ApiException : ApiException + { + public TResult Result { get; private set; } + + public ApiException(string message, int statusCode, string? response, System.Collections.Generic.IReadOnlyDictionary> headers, TResult result, System.Exception? innerException) + : base(message, statusCode, response, headers, innerException) + { + Result = result; + } + } + +} + +#pragma warning restore 108 +#pragma warning restore 114 +#pragma warning restore 472 +#pragma warning restore 612 +#pragma warning restore 649 +#pragma warning restore 1573 +#pragma warning restore 1591 +#pragma warning restore 8073 +#pragma warning restore 3016 +#pragma warning restore 8600 +#pragma warning restore 8602 +#pragma warning restore 8603 +#pragma warning restore 8604 +#pragma warning restore 8625 +#pragma warning restore 8765 \ No newline at end of file diff --git a/nswag-spike/generated/FunctionsService.ready.json b/nswag-spike/generated/FunctionsService.ready.json new file mode 100644 index 00000000..57295bb6 --- /dev/null +++ b/nswag-spike/generated/FunctionsService.ready.json @@ -0,0 +1,330 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Supabase Functions API", + "version": "1.0" + }, + "paths": { + "/functions/v1/{functionName}": { + "delete": { + "operationId": "InvokeFunctionDelete", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionDelete 200 response", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + }, + "get": { + "operationId": "InvokeFunctionGet", + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionGet 200 response", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + }, + "patch": { + "operationId": "InvokeFunctionPatch", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionPatch 200 response", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + }, + "post": { + "operationId": "InvokeFunctionPost", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionPost 200 response", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + }, + "put": { + "operationId": "InvokeFunctionPut", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionPut 200 response", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "FunctionsErrorResponseContent": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + }, + "StringMap": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Generic string-to-string map \u2014 used for arbitrary query parameter collections\n(e.g. PostgREST filter params, RPC GET arguments)." + } + } + } +} \ No newline at end of file diff --git a/nswag-spike/generated/StorageClient.cs b/nswag-spike/generated/StorageClient.cs new file mode 100644 index 00000000..c076ffc6 --- /dev/null +++ b/nswag-spike/generated/StorageClient.cs @@ -0,0 +1,2789 @@ +//---------------------- +// +// Generated using the NSwag toolchain v14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) +// +//---------------------- + +#nullable enable + +#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended." +#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." +#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' +#pragma warning disable 612 // Disable "CS0612 '...' is obsolete" +#pragma warning disable 649 // Disable "CS0649 Field is never assigned to, and will always have its default value null" +#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... +#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." +#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'" +#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant" +#pragma warning disable 8600 // Disable "CS8600 Converting null literal or possible null value to non-nullable type" +#pragma warning disable 8602 // Disable "CS8602 Dereference of a possibly null reference" +#pragma warning disable 8603 // Disable "CS8603 Possible null reference return" +#pragma warning disable 8604 // Disable "CS8604 Possible null reference argument for parameter" +#pragma warning disable 8625 // Disable "CS8625 Cannot convert null literal to non-nullable reference type" +#pragma warning disable 8765 // Disable "CS8765 Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes)." + +namespace Supabase.Storage.Gen +{ + using System = global::System; + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial interface IStorageClient + { + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// ListBuckets 200 response + /// A server side error occurred. + System.Threading.Tasks.Task> ListBucketsAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// CreateBucket 200 response + /// A server side error occurred. + System.Threading.Tasks.Task CreateBucketAsync(CreateBucketRequestContent body, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// DeleteBucket 200 response + /// A server side error occurred. + System.Threading.Tasks.Task DeleteBucketAsync(string id, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// GetBucket 200 response + /// A server side error occurred. + System.Threading.Tasks.Task GetBucketAsync(string id, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// UpdateBucket 200 response + /// A server side error occurred. + System.Threading.Tasks.Task UpdateBucketAsync(UpdateBucketRequestContent body, string id, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// EmptyBucket 200 response + /// A server side error occurred. + System.Threading.Tasks.Task EmptyBucketAsync(string id, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// CopyObject 200 response + /// A server side error occurred. + System.Threading.Tasks.Task CopyObjectAsync(CopyObjectRequestContent body, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// GetObjectInfo 200 response + /// A server side error occurred. + System.Threading.Tasks.Task GetObjectInfoAsync(string bucketId, string wildcardPath, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// ListObjects 200 response + /// A server side error occurred. + System.Threading.Tasks.Task> ListObjectsAsync(ListObjectsRequestContent body, string bucketId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// MoveObject 200 response + /// A server side error occurred. + System.Threading.Tasks.Task MoveObjectAsync(MoveObjectRequestContent body, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// CreateSignedUrls 200 response + /// A server side error occurred. + System.Threading.Tasks.Task> CreateSignedUrlsAsync(CreateSignedUrlsRequestContent body, string bucketId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// CreateSignedUrl 200 response + /// A server side error occurred. + System.Threading.Tasks.Task CreateSignedUrlAsync(CreateSignedUrlRequestContent body, string bucketId, string wildcardPath, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// CreateSignedUploadUrl 200 response + /// A server side error occurred. + System.Threading.Tasks.Task CreateSignedUploadUrlAsync(string bucketId, string wildcardPath, string? x_upsert = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// DeleteObjects 200 response + /// A server side error occurred. + System.Threading.Tasks.Task> DeleteObjectsAsync(DeleteObjectsRequestContent body, string bucketId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// HeadObject 200 response + /// A server side error occurred. + System.Threading.Tasks.Task HeadObjectAsync(string bucketId, string wildcardPath, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Upload a new object. Body is multipart/form-data with a required file part. + ///
Smithy has no native multipart/form-data support; the @httpMultipartForm trait + ///
documents intent and patch-openapi.py injects the correct requestBody schema. + ///
+ /// UploadObject 200 response + /// A server side error occurred. + System.Threading.Tasks.Task UploadObjectAsync(string bucketId, string wildcardPath, string? x_upsert = null, FileParameter file = null, string? cacheControl = null, object? metadata = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Replace an existing object. Body is multipart/form-data (see UploadObject). + /// + /// UpdateObject 200 response + /// A server side error occurred. + System.Threading.Tasks.Task UpdateObjectAsync(string bucketId, string wildcardPath, FileParameter file = null, string? cacheControl = null, object? metadata = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Step 1: Create a new TUS upload session. + ///
The server responds with a Location header containing the upload URL. + ///
+ /// Total size of the file in bytes. + /// Base64-encoded TUS metadata (bucketName, objectName, contentType, cacheControl). + /// Set to "true" to overwrite an existing object at the same path. + /// CreateTusUpload 201 response + /// A server side error occurred. + System.Threading.Tasks.Task CreateTusUploadAsync(string tus_Resumable, double upload_Length, string upload_Metadata, string? x_upsert = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Step 3: Query the server-side offset of a TUS session (used when resuming). + /// + /// GetUploadOffset 200 response + /// A server side error occurred. + System.Threading.Tasks.Task GetUploadOffsetAsync(string uploadId, string tus_Resumable, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Step 2: Upload a chunk of data to an existing TUS session. + ///
Repeat with increasing Upload-Offset until all bytes are sent. + ///
+ /// Byte offset at which this chunk begins. + /// UploadChunk 204 response + /// A server side error occurred. + System.Threading.Tasks.Task UploadChunkAsync(System.IO.Stream body, string uploadId, string tus_Resumable, double upload_Offset, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class StorageClient : IStorageClient + { + private System.Net.Http.HttpClient _httpClient; + private static System.Lazy _settings = new System.Lazy(CreateSerializerSettings, true); + private System.Text.Json.JsonSerializerOptions _instanceSettings; + + #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + public StorageClient(System.Net.Http.HttpClient httpClient) + #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + { + _httpClient = httpClient; + Initialize(); + } + + private static System.Text.Json.JsonSerializerOptions CreateSerializerSettings() + { + var settings = new System.Text.Json.JsonSerializerOptions(); + UpdateJsonSerializerSettings(settings); + return settings; + } + + protected System.Text.Json.JsonSerializerOptions JsonSerializerSettings { get { return _instanceSettings ?? _settings.Value; } } + + static partial void UpdateJsonSerializerSettings(System.Text.Json.JsonSerializerOptions settings); + + partial void Initialize(); + + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url); + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); + partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// ListBuckets 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task> ListBucketsAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "bucket" + urlBuilder_.Append("bucket"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// CreateBucket 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CreateBucketAsync(CreateBucketRequestContent body, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); + var content_ = new System.Net.Http.ByteArrayContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "bucket" + urlBuilder_.Append("bucket"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// DeleteBucket 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task DeleteBucketAsync(string id, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (id == null) + throw new System.ArgumentNullException("id"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("DELETE"); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "bucket/{id}" + urlBuilder_.Append("bucket/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// GetBucket 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetBucketAsync(string id, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (id == null) + throw new System.ArgumentNullException("id"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "bucket/{id}" + urlBuilder_.Append("bucket/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// UpdateBucket 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task UpdateBucketAsync(UpdateBucketRequestContent body, string id, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (id == null) + throw new System.ArgumentNullException("id"); + + if (body == null) + throw new System.ArgumentNullException("body"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); + var content_ = new System.Net.Http.ByteArrayContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("PUT"); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "bucket/{id}" + urlBuilder_.Append("bucket/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// EmptyBucket 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task EmptyBucketAsync(string id, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (id == null) + throw new System.ArgumentNullException("id"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("POST"); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "bucket/{id}/empty" + urlBuilder_.Append("bucket/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/empty"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// CopyObject 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CopyObjectAsync(CopyObjectRequestContent body, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); + var content_ = new System.Net.Http.ByteArrayContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "object/copy" + urlBuilder_.Append("object/copy"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// GetObjectInfo 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetObjectInfoAsync(string bucketId, string wildcardPath, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (bucketId == null) + throw new System.ArgumentNullException("bucketId"); + + if (wildcardPath == null) + throw new System.ArgumentNullException("wildcardPath"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "object/info/{bucketId}/{wildcardPath}" + urlBuilder_.Append("object/info/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(bucketId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(wildcardPath, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// ListObjects 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task> ListObjectsAsync(ListObjectsRequestContent body, string bucketId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (bucketId == null) + throw new System.ArgumentNullException("bucketId"); + + if (body == null) + throw new System.ArgumentNullException("body"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); + var content_ = new System.Net.Http.ByteArrayContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "object/list/{bucketId}" + urlBuilder_.Append("object/list/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(bucketId, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// MoveObject 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task MoveObjectAsync(MoveObjectRequestContent body, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); + var content_ = new System.Net.Http.ByteArrayContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "object/move" + urlBuilder_.Append("object/move"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// CreateSignedUrls 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task> CreateSignedUrlsAsync(CreateSignedUrlsRequestContent body, string bucketId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (bucketId == null) + throw new System.ArgumentNullException("bucketId"); + + if (body == null) + throw new System.ArgumentNullException("body"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); + var content_ = new System.Net.Http.ByteArrayContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "object/sign/{bucketId}" + urlBuilder_.Append("object/sign/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(bucketId, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// CreateSignedUrl 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CreateSignedUrlAsync(CreateSignedUrlRequestContent body, string bucketId, string wildcardPath, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (bucketId == null) + throw new System.ArgumentNullException("bucketId"); + + if (wildcardPath == null) + throw new System.ArgumentNullException("wildcardPath"); + + if (body == null) + throw new System.ArgumentNullException("body"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); + var content_ = new System.Net.Http.ByteArrayContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "object/sign/{bucketId}/{wildcardPath}" + urlBuilder_.Append("object/sign/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(bucketId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(wildcardPath, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// CreateSignedUploadUrl 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CreateSignedUploadUrlAsync(string bucketId, string wildcardPath, string? x_upsert = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (bucketId == null) + throw new System.ArgumentNullException("bucketId"); + + if (wildcardPath == null) + throw new System.ArgumentNullException("wildcardPath"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (x_upsert != null) + request_.Headers.TryAddWithoutValidation("x-upsert", ConvertToString(x_upsert, System.Globalization.CultureInfo.InvariantCulture)); + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "object/upload/sign/{bucketId}/{wildcardPath}" + urlBuilder_.Append("object/upload/sign/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(bucketId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(wildcardPath, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// DeleteObjects 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task> DeleteObjectsAsync(DeleteObjectsRequestContent body, string bucketId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (bucketId == null) + throw new System.ArgumentNullException("bucketId"); + + if (body == null) + throw new System.ArgumentNullException("body"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, JsonSerializerSettings); + var content_ = new System.Net.Http.ByteArrayContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("DELETE"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "object/{bucketId}" + urlBuilder_.Append("object/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(bucketId, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// HeadObject 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task HeadObjectAsync(string bucketId, string wildcardPath, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (bucketId == null) + throw new System.ArgumentNullException("bucketId"); + + if (wildcardPath == null) + throw new System.ArgumentNullException("wildcardPath"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("HEAD"); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "object/{bucketId}/{wildcardPath}" + urlBuilder_.Append("object/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(bucketId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(wildcardPath, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Upload a new object. Body is multipart/form-data with a required file part. + ///
Smithy has no native multipart/form-data support; the @httpMultipartForm trait + ///
documents intent and patch-openapi.py injects the correct requestBody schema. + ///
+ /// UploadObject 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task UploadObjectAsync(string bucketId, string wildcardPath, string? x_upsert = null, FileParameter file = null, string? cacheControl = null, object? metadata = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (bucketId == null) + throw new System.ArgumentNullException("bucketId"); + + if (wildcardPath == null) + throw new System.ArgumentNullException("wildcardPath"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (x_upsert != null) + request_.Headers.TryAddWithoutValidation("x-upsert", ConvertToString(x_upsert, System.Globalization.CultureInfo.InvariantCulture)); + var boundary_ = System.Guid.NewGuid().ToString(); + var content_ = new System.Net.Http.MultipartFormDataContent(boundary_); + content_.Headers.Remove("Content-Type"); + content_.Headers.TryAddWithoutValidation("Content-Type", "multipart/form-data; boundary=" + boundary_); + + if (file == null) + throw new System.ArgumentNullException("file"); + else + { + var content_file_ = new System.Net.Http.StreamContent(file.Data); + if (!string.IsNullOrEmpty(file.ContentType)) + content_file_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse(file.ContentType); + content_.Add(content_file_, "file", file.FileName ?? "file"); + } + + if (cacheControl == null) + throw new System.ArgumentNullException("cacheControl"); + else + { + content_.Add(new System.Net.Http.StringContent(ConvertToString(cacheControl, System.Globalization.CultureInfo.InvariantCulture)), "cacheControl"); + } + + if (metadata == null) + throw new System.ArgumentNullException("metadata"); + else + { + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(metadata, JsonSerializerSettings); + content_.Add(new System.Net.Http.ByteArrayContent(json_), "metadata"); + } + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "object/{bucketId}/{wildcardPath}" + urlBuilder_.Append("object/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(bucketId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(wildcardPath, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Replace an existing object. Body is multipart/form-data (see UploadObject). + /// + /// UpdateObject 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task UpdateObjectAsync(string bucketId, string wildcardPath, FileParameter file = null, string? cacheControl = null, object? metadata = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (bucketId == null) + throw new System.ArgumentNullException("bucketId"); + + if (wildcardPath == null) + throw new System.ArgumentNullException("wildcardPath"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var boundary_ = System.Guid.NewGuid().ToString(); + var content_ = new System.Net.Http.MultipartFormDataContent(boundary_); + content_.Headers.Remove("Content-Type"); + content_.Headers.TryAddWithoutValidation("Content-Type", "multipart/form-data; boundary=" + boundary_); + + if (file == null) + throw new System.ArgumentNullException("file"); + else + { + var content_file_ = new System.Net.Http.StreamContent(file.Data); + if (!string.IsNullOrEmpty(file.ContentType)) + content_file_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse(file.ContentType); + content_.Add(content_file_, "file", file.FileName ?? "file"); + } + + if (cacheControl == null) + throw new System.ArgumentNullException("cacheControl"); + else + { + content_.Add(new System.Net.Http.StringContent(ConvertToString(cacheControl, System.Globalization.CultureInfo.InvariantCulture)), "cacheControl"); + } + + if (metadata == null) + throw new System.ArgumentNullException("metadata"); + else + { + var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(metadata, JsonSerializerSettings); + content_.Add(new System.Net.Http.ByteArrayContent(json_), "metadata"); + } + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("PUT"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "object/{bucketId}/{wildcardPath}" + urlBuilder_.Append("object/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(bucketId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(wildcardPath, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Step 1: Create a new TUS upload session. + ///
The server responds with a Location header containing the upload URL. + ///
+ /// Total size of the file in bytes. + /// Base64-encoded TUS metadata (bucketName, objectName, contentType, cacheControl). + /// Set to "true" to overwrite an existing object at the same path. + /// CreateTusUpload 201 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CreateTusUploadAsync(string tus_Resumable, double upload_Length, string upload_Metadata, string? x_upsert = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (tus_Resumable == null) + throw new System.ArgumentNullException("tus_Resumable"); + request_.Headers.TryAddWithoutValidation("Tus-Resumable", ConvertToString(tus_Resumable, System.Globalization.CultureInfo.InvariantCulture)); + + if (upload_Length == null) + throw new System.ArgumentNullException("upload_Length"); + request_.Headers.TryAddWithoutValidation("Upload-Length", ConvertToString(upload_Length, System.Globalization.CultureInfo.InvariantCulture)); + + if (upload_Metadata == null) + throw new System.ArgumentNullException("upload_Metadata"); + request_.Headers.TryAddWithoutValidation("Upload-Metadata", ConvertToString(upload_Metadata, System.Globalization.CultureInfo.InvariantCulture)); + + if (x_upsert != null) + request_.Headers.TryAddWithoutValidation("x-upsert", ConvertToString(x_upsert, System.Globalization.CultureInfo.InvariantCulture)); + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("POST"); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "upload/resumable" + urlBuilder_.Append("upload/resumable"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 201) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Step 3: Query the server-side offset of a TUS session (used when resuming). + /// + /// GetUploadOffset 200 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetUploadOffsetAsync(string uploadId, string tus_Resumable, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (uploadId == null) + throw new System.ArgumentNullException("uploadId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (tus_Resumable == null) + throw new System.ArgumentNullException("tus_Resumable"); + request_.Headers.TryAddWithoutValidation("Tus-Resumable", ConvertToString(tus_Resumable, System.Globalization.CultureInfo.InvariantCulture)); + request_.Method = new System.Net.Http.HttpMethod("HEAD"); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "upload/resumable/{uploadId}" + urlBuilder_.Append("upload/resumable/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(uploadId, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Step 2: Upload a chunk of data to an existing TUS session. + ///
Repeat with increasing Upload-Offset until all bytes are sent. + ///
+ /// Byte offset at which this chunk begins. + /// UploadChunk 204 response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task UploadChunkAsync(System.IO.Stream body, string uploadId, string tus_Resumable, double upload_Offset, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + { + if (uploadId == null) + throw new System.ArgumentNullException("uploadId"); + + if (body == null) + throw new System.ArgumentNullException("body"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + + if (tus_Resumable == null) + throw new System.ArgumentNullException("tus_Resumable"); + request_.Headers.TryAddWithoutValidation("Tus-Resumable", ConvertToString(tus_Resumable, System.Globalization.CultureInfo.InvariantCulture)); + + if (upload_Offset == null) + throw new System.ArgumentNullException("upload_Offset"); + request_.Headers.TryAddWithoutValidation("Upload-Offset", ConvertToString(upload_Offset, System.Globalization.CultureInfo.InvariantCulture)); + var content_ = new System.Net.Http.StreamContent(body); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/octet-stream"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("PATCH"); + + var urlBuilder_ = new System.Text.StringBuilder(); + + // Operation Path: "upload/resumable/{uploadId}" + urlBuilder_.Append("upload/resumable/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(uploadId, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 204) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("StorageError 400 response", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await ReadAsStringAsync(response_.Content, cancellationToken).ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + protected struct ObjectResponseResult + { + public ObjectResponseResult(T responseObject, string responseText) + { + this.Object = responseObject; + this.Text = responseText; + } + + public T Object { get; } + + public string Text { get; } + } + + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + private static System.Threading.Tasks.Task ReadAsStringAsync(System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) + { + #if NET5_0_OR_GREATER + return content.ReadAsStringAsync(cancellationToken); + #else + return content.ReadAsStringAsync(); + #endif + } + + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + private static System.Threading.Tasks.Task ReadAsStreamAsync(System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) + { + #if NET5_0_OR_GREATER + return content.ReadAsStreamAsync(cancellationToken); + #else + return content.ReadAsStreamAsync(); + #endif + } + + public bool ReadResponseAsString { get; set; } + + protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) + { + if (response == null || response.Content == null) + { + return new ObjectResponseResult(default(T)!, string.Empty); + } + + if (ReadResponseAsString) + { + var responseText = await ReadAsStringAsync(response.Content, cancellationToken).ConfigureAwait(false); + try + { + var typedBody = System.Text.Json.JsonSerializer.Deserialize(responseText, JsonSerializerSettings); + return new ObjectResponseResult(typedBody!, responseText); + } + catch (System.Text.Json.JsonException exception) + { + var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception); + } + } + else + { + try + { + using (var responseStream = await ReadAsStreamAsync(response.Content, cancellationToken).ConfigureAwait(false)) + { + var typedBody = await System.Text.Json.JsonSerializer.DeserializeAsync(responseStream, JsonSerializerSettings, cancellationToken).ConfigureAwait(false); + return new ObjectResponseResult(typedBody!, string.Empty); + } + } + catch (System.Text.Json.JsonException exception) + { + var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception); + } + } + } + + private string ConvertToString(object? value, System.Globalization.CultureInfo cultureInfo) + { + if (value == null) + { + return ""; + } + + if (value is System.Enum) + { + var name = System.Enum.GetName(value.GetType(), value); + if (name != null) + { + var field_ = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); + if (field_ != null) + { + var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field_, typeof(System.Runtime.Serialization.EnumMemberAttribute)) + as System.Runtime.Serialization.EnumMemberAttribute; + if (attribute != null) + { + return attribute.Value != null ? attribute.Value : name; + } + } + + var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); + return converted == null ? string.Empty : converted; + } + } + else if (value is bool) + { + return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); + } + else if (value is byte[]) + { + return System.Convert.ToBase64String((byte[]) value); + } + else if (value is string[]) + { + return string.Join(",", (string[])value); + } + else if (value.GetType().IsArray) + { + var valueArray = (System.Array)value; + var valueTextArray = new string[valueArray.Length]; + for (var i = 0; i < valueArray.Length; i++) + { + valueTextArray[i] = ConvertToString(valueArray.GetValue(i), cultureInfo); + } + return string.Join(",", valueTextArray); + } + + var result = System.Convert.ToString(value, cultureInfo); + return result == null ? "" : result; + } + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Bucket + { + + [System.Text.Json.Serialization.JsonPropertyName("id")] + public string Id { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("name")] + public string Name { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("public")] + public bool Public { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("file_size_limit")] + public double? File_size_limit { get; set; } = default!; + + /// + /// Common string list shape reused across services. + /// + [System.Text.Json.Serialization.JsonPropertyName("allowed_mime_types")] + public System.Collections.Generic.ICollection Allowed_mime_types { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("created_at")] + public string Created_at { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("updated_at")] + public string Updated_at { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class CopyObjectRequestContent + { + + [System.Text.Json.Serialization.JsonPropertyName("bucketId")] + public string BucketId { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("sourceKey")] + public string SourceKey { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("destinationKey")] + public string DestinationKey { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("destinationBucket")] + public string DestinationBucket { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class CopyObjectResponseContent + { + + [System.Text.Json.Serialization.JsonPropertyName("Key")] + public string Key { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class CreateBucketRequestContent + { + + [System.Text.Json.Serialization.JsonPropertyName("id")] + public string Id { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("name")] + public string Name { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("public")] + public bool Public { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("file_size_limit")] + public double? File_size_limit { get; set; } = default!; + + /// + /// Common string list shape reused across services. + /// + [System.Text.Json.Serialization.JsonPropertyName("allowed_mime_types")] + public System.Collections.Generic.ICollection Allowed_mime_types { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class CreateSignedUploadUrlResponseContent + { + + [System.Text.Json.Serialization.JsonPropertyName("url")] + public string Url { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class CreateSignedUrlRequestContent + { + + [System.Text.Json.Serialization.JsonPropertyName("expiresIn")] + public double ExpiresIn { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class CreateSignedUrlResponseContent + { + + [System.Text.Json.Serialization.JsonPropertyName("signedURL")] + public string SignedURL { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class CreateSignedUrlsRequestContent + { + + [System.Text.Json.Serialization.JsonPropertyName("expiresIn")] + public double ExpiresIn { get; set; } = default!; + + /// + /// Common string list shape reused across services. + /// + [System.Text.Json.Serialization.JsonPropertyName("paths")] + public System.Collections.Generic.ICollection Paths { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DeleteObjectsRequestContent + { + + /// + /// Common string list shape reused across services. + /// + [System.Text.Json.Serialization.JsonPropertyName("prefixes")] + public System.Collections.Generic.ICollection Prefixes { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class FileMetadata + { + + [System.Text.Json.Serialization.JsonPropertyName("eTag")] + public string ETag { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("size")] + public double? Size { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("mimetype")] + public string Mimetype { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("cacheControl")] + public string CacheControl { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("lastModified")] + public string LastModified { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("contentLength")] + public double? ContentLength { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("httpStatusCode")] + public double? HttpStatusCode { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class FileObject + { + + [System.Text.Json.Serialization.JsonPropertyName("name")] + public string Name { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("id")] + public string Id { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("updated_at")] + public string Updated_at { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("created_at")] + public string Created_at { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("last_accessed_at")] + public string Last_accessed_at { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("metadata")] + public FileMetadata Metadata { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class GetBucketResponseContent + { + + [System.Text.Json.Serialization.JsonPropertyName("id")] + public string Id { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("name")] + public string Name { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("public")] + public bool Public { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("file_size_limit")] + public double? File_size_limit { get; set; } = default!; + + /// + /// Common string list shape reused across services. + /// + [System.Text.Json.Serialization.JsonPropertyName("allowed_mime_types")] + public System.Collections.Generic.ICollection Allowed_mime_types { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("created_at")] + public string Created_at { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("updated_at")] + public string Updated_at { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class GetObjectInfoResponseContent + { + + [System.Text.Json.Serialization.JsonPropertyName("eTag")] + public string ETag { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("size")] + public double? Size { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("mimetype")] + public string Mimetype { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("cacheControl")] + public string CacheControl { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("lastModified")] + public string LastModified { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("contentLength")] + public double? ContentLength { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("httpStatusCode")] + public double? HttpStatusCode { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ListObjectsRequestContent + { + + [System.Text.Json.Serialization.JsonPropertyName("prefix")] + public string Prefix { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("limit")] + public double? Limit { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("offset")] + public double? Offset { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("sortBy")] + public SortBy SortBy { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class MoveObjectRequestContent + { + + [System.Text.Json.Serialization.JsonPropertyName("bucketId")] + public string BucketId { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("sourceKey")] + public string SourceKey { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("destinationKey")] + public string DestinationKey { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("destinationBucket")] + public string DestinationBucket { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class SignedUrlResult + { + + [System.Text.Json.Serialization.JsonPropertyName("signedURL")] + public string SignedURL { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("path")] + public string Path { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("error")] + public string Error { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class SortBy + { + + [System.Text.Json.Serialization.JsonPropertyName("column")] + public string Column { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("order")] + public string Order { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class StorageErrorResponseContent + { + + [System.Text.Json.Serialization.JsonPropertyName("message")] + public string Message { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("error")] + public string Error { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("statusCode")] + public string StatusCode { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class UpdateBucketRequestContent + { + + [System.Text.Json.Serialization.JsonPropertyName("public")] + public bool Public { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("file_size_limit")] + public double? File_size_limit { get; set; } = default!; + + /// + /// Common string list shape reused across services. + /// + [System.Text.Json.Serialization.JsonPropertyName("allowed_mime_types")] + public System.Collections.Generic.ICollection Allowed_mime_types { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class UpdateObjectResponseContent + { + + [System.Text.Json.Serialization.JsonPropertyName("Key")] + public string Key { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("Id")] + public string Id { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class UploadObjectResponseContent + { + + [System.Text.Json.Serialization.JsonPropertyName("Key")] + public string Key { get; set; } = default!; + + [System.Text.Json.Serialization.JsonPropertyName("Id")] + public string Id { get; set; } = default!; + + private System.Collections.Generic.IDictionary? _additionalProperties; + + [System.Text.Json.Serialization.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class FileParameter + { + public FileParameter(System.IO.Stream data) + : this (data, null, null) + { + } + + public FileParameter(System.IO.Stream data, string? fileName) + : this (data, fileName, null) + { + } + + public FileParameter(System.IO.Stream data, string? fileName, string? contentType) + { + Data = data; + FileName = fileName; + ContentType = contentType; + } + + public System.IO.Stream Data { get; private set; } + + public string? FileName { get; private set; } + + public string? ContentType { get; private set; } + } + + + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ApiException : System.Exception + { + public int StatusCode { get; private set; } + + public string? Response { get; private set; } + + public System.Collections.Generic.IReadOnlyDictionary> Headers { get; private set; } + + public ApiException(string message, int statusCode, string? response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Exception? innerException) + : base(message + "\n\nStatus: " + statusCode + "\nResponse: \n" + ((response == null) ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException) + { + StatusCode = statusCode; + Response = response; + Headers = headers; + } + + public override string ToString() + { + return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString()); + } + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ApiException : ApiException + { + public TResult Result { get; private set; } + + public ApiException(string message, int statusCode, string? response, System.Collections.Generic.IReadOnlyDictionary> headers, TResult result, System.Exception? innerException) + : base(message, statusCode, response, headers, innerException) + { + Result = result; + } + } + +} + +#pragma warning restore 108 +#pragma warning restore 114 +#pragma warning restore 472 +#pragma warning restore 612 +#pragma warning restore 649 +#pragma warning restore 1573 +#pragma warning restore 1591 +#pragma warning restore 8073 +#pragma warning restore 3016 +#pragma warning restore 8600 +#pragma warning restore 8602 +#pragma warning restore 8603 +#pragma warning restore 8604 +#pragma warning restore 8625 +#pragma warning restore 8765 \ No newline at end of file diff --git a/nswag-spike/generated/StorageService.ready.json b/nswag-spike/generated/StorageService.ready.json new file mode 100644 index 00000000..49f2dec5 --- /dev/null +++ b/nswag-spike/generated/StorageService.ready.json @@ -0,0 +1,1365 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Supabase Storage API", + "version": "1.0" + }, + "paths": { + "/bucket": { + "get": { + "operationId": "ListBuckets", + "responses": { + "200": { + "description": "ListBuckets 200 response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Bucket" + } + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "post": { + "operationId": "CreateBucket", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateBucketRequestContent" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "CreateBucket 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/bucket/{id}": { + "delete": { + "operationId": "DeleteBucket", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "DeleteBucket 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "get": { + "operationId": "GetBucket", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "GetBucket 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetBucketResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "put": { + "operationId": "UpdateBucket", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateBucketRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "UpdateBucket 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/bucket/{id}/empty": { + "post": { + "operationId": "EmptyBucket", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "EmptyBucket 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/copy": { + "post": { + "operationId": "CopyObject", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CopyObjectRequestContent" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "CopyObject 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CopyObjectResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/info/{bucketId}/{wildcardPath}": { + "get": { + "operationId": "GetObjectInfo", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "GetObjectInfo 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetObjectInfoResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/list/{bucketId}": { + "post": { + "operationId": "ListObjects", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListObjectsRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "ListObjects 200 response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileObject" + } + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/move": { + "post": { + "operationId": "MoveObject", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MoveObjectRequestContent" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "MoveObject 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/sign/{bucketId}": { + "post": { + "operationId": "CreateSignedUrls", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSignedUrlsRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "CreateSignedUrls 200 response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SignedUrlResult" + } + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/sign/{bucketId}/{wildcardPath}": { + "post": { + "operationId": "CreateSignedUrl", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSignedUrlRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "CreateSignedUrl 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSignedUrlResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/upload/sign/{bucketId}/{wildcardPath}": { + "post": { + "operationId": "CreateSignedUploadUrl", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "x-upsert", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "CreateSignedUploadUrl 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSignedUploadUrlResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/{bucketId}": { + "delete": { + "operationId": "DeleteObjects", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteObjectsRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "DeleteObjects 200 response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileObject" + } + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/{bucketId}/{wildcardPath}": { + "head": { + "operationId": "HeadObject", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "HeadObject 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "post": { + "description": "Upload a new object. Body is multipart/form-data with a required file part.\nSmithy has no native multipart/form-data support; the @httpMultipartForm trait\ndocuments intent and patch-openapi.py injects the correct requestBody schema.", + "operationId": "UploadObject", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "x-upsert", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "UploadObject 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UploadObjectResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + }, + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "required": [ + "file" + ], + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "cacheControl": { + "type": "string" + }, + "metadata": { + "type": "object" + } + } + } + } + } + } + }, + "put": { + "description": "Replace an existing object. Body is multipart/form-data (see UploadObject).", + "operationId": "UpdateObject", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "UpdateObject 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateObjectResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + }, + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "required": [ + "file" + ], + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "cacheControl": { + "type": "string" + }, + "metadata": { + "type": "object" + } + } + } + } + } + } + } + }, + "/upload/resumable": { + "post": { + "description": "Step 1: Create a new TUS upload session.\nThe server responds with a Location header containing the upload URL.", + "operationId": "CreateTusUpload", + "parameters": [ + { + "name": "Tus-Resumable", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "Upload-Length", + "in": "header", + "description": "Total size of the file in bytes.", + "schema": { + "type": "number", + "description": "Total size of the file in bytes." + }, + "required": true + }, + { + "name": "Upload-Metadata", + "in": "header", + "description": "Base64-encoded TUS metadata (bucketName, objectName, contentType, cacheControl).", + "schema": { + "type": "string", + "description": "Base64-encoded TUS metadata (bucketName, objectName, contentType, cacheControl)." + }, + "required": true + }, + { + "name": "x-upsert", + "in": "header", + "description": "Set to \"true\" to overwrite an existing object at the same path.", + "schema": { + "type": "string", + "description": "Set to \"true\" to overwrite an existing object at the same path." + } + } + ], + "responses": { + "201": { + "description": "CreateTusUpload 201 response", + "headers": { + "Location": { + "description": "Full URL of the created upload session. Used in subsequent PATCH/HEAD requests.", + "schema": { + "type": "string", + "description": "Full URL of the created upload session. Used in subsequent PATCH/HEAD requests." + }, + "required": true + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/upload/resumable/{uploadId}": { + "head": { + "description": "Step 3: Query the server-side offset of a TUS session (used when resuming).", + "operationId": "GetUploadOffset", + "parameters": [ + { + "name": "uploadId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "Tus-Resumable", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "GetUploadOffset 200 response", + "headers": { + "Upload-Offset": { + "schema": { + "type": "number" + }, + "required": true + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "patch": { + "description": "Step 2: Upload a chunk of data to an existing TUS session.\nRepeat with increasing Upload-Offset until all bytes are sent.", + "operationId": "UploadChunk", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "uploadId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "Tus-Resumable", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "Upload-Offset", + "in": "header", + "description": "Byte offset at which this chunk begins.", + "schema": { + "type": "number", + "description": "Byte offset at which this chunk begins." + }, + "required": true + } + ], + "responses": { + "204": { + "description": "UploadChunk 204 response", + "headers": { + "Upload-Offset": { + "description": "New server-side offset after the chunk was accepted.", + "schema": { + "type": "number", + "description": "New server-side offset after the chunk was accepted." + }, + "required": true + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Bucket": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "public": { + "type": "boolean" + }, + "file_size_limit": { + "type": "number", + "nullable": true + }, + "allowed_mime_types": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "public" + ] + }, + "CopyObjectRequestContent": { + "type": "object", + "properties": { + "bucketId": { + "type": "string" + }, + "sourceKey": { + "type": "string" + }, + "destinationKey": { + "type": "string" + }, + "destinationBucket": { + "type": "string" + } + }, + "required": [ + "bucketId", + "destinationKey", + "sourceKey" + ] + }, + "CopyObjectResponseContent": { + "type": "object", + "properties": { + "Key": { + "type": "string" + } + }, + "required": [ + "Key" + ] + }, + "CreateBucketRequestContent": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "public": { + "type": "boolean" + }, + "file_size_limit": { + "type": "number", + "nullable": true + }, + "allowed_mime_types": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + } + }, + "required": [ + "id", + "name", + "public" + ] + }, + "CreateSignedUploadUrlResponseContent": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + }, + "required": [ + "url" + ] + }, + "CreateSignedUrlRequestContent": { + "type": "object", + "properties": { + "expiresIn": { + "type": "number" + } + }, + "required": [ + "expiresIn" + ] + }, + "CreateSignedUrlResponseContent": { + "type": "object", + "properties": { + "signedURL": { + "type": "string" + } + }, + "required": [ + "signedURL" + ] + }, + "CreateSignedUrlsRequestContent": { + "type": "object", + "properties": { + "expiresIn": { + "type": "number" + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + } + }, + "required": [ + "expiresIn", + "paths" + ] + }, + "DeleteObjectsRequestContent": { + "type": "object", + "properties": { + "prefixes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + } + }, + "required": [ + "prefixes" + ] + }, + "FileMetadata": { + "type": "object", + "properties": { + "eTag": { + "type": "string" + }, + "size": { + "type": "number", + "nullable": true + }, + "mimetype": { + "type": "string" + }, + "cacheControl": { + "type": "string" + }, + "lastModified": { + "type": "string" + }, + "contentLength": { + "type": "number", + "nullable": true + }, + "httpStatusCode": { + "type": "number", + "nullable": true + } + } + }, + "FileObject": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "id": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "last_accessed_at": { + "type": "string" + }, + "metadata": { + "$ref": "#/components/schemas/FileMetadata" + } + }, + "required": [ + "name" + ] + }, + "GetBucketResponseContent": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "public": { + "type": "boolean" + }, + "file_size_limit": { + "type": "number", + "nullable": true + }, + "allowed_mime_types": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "public" + ] + }, + "GetObjectInfoResponseContent": { + "type": "object", + "properties": { + "eTag": { + "type": "string" + }, + "size": { + "type": "number", + "nullable": true + }, + "mimetype": { + "type": "string" + }, + "cacheControl": { + "type": "string" + }, + "lastModified": { + "type": "string" + }, + "contentLength": { + "type": "number", + "nullable": true + }, + "httpStatusCode": { + "type": "number", + "nullable": true + } + } + }, + "ListObjectsRequestContent": { + "type": "object", + "properties": { + "prefix": { + "type": "string" + }, + "limit": { + "type": "number", + "nullable": true + }, + "offset": { + "type": "number", + "nullable": true + }, + "sortBy": { + "$ref": "#/components/schemas/SortBy" + } + }, + "required": [ + "prefix" + ] + }, + "MoveObjectRequestContent": { + "type": "object", + "properties": { + "bucketId": { + "type": "string" + }, + "sourceKey": { + "type": "string" + }, + "destinationKey": { + "type": "string" + }, + "destinationBucket": { + "type": "string" + } + }, + "required": [ + "bucketId", + "destinationKey", + "sourceKey" + ] + }, + "SignedUrlResult": { + "type": "object", + "properties": { + "signedURL": { + "type": "string" + }, + "path": { + "type": "string" + }, + "error": { + "type": "string" + } + }, + "required": [ + "path" + ] + }, + "SortBy": { + "type": "object", + "properties": { + "column": { + "type": "string" + }, + "order": { + "type": "string" + } + } + }, + "StorageErrorResponseContent": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "error": { + "type": "string" + }, + "statusCode": { + "type": "string" + } + } + }, + "UpdateBucketRequestContent": { + "type": "object", + "properties": { + "public": { + "type": "boolean" + }, + "file_size_limit": { + "type": "number", + "nullable": true + }, + "allowed_mime_types": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + } + }, + "required": [ + "public" + ] + }, + "UpdateObjectResponseContent": { + "type": "object", + "properties": { + "Key": { + "type": "string" + }, + "Id": { + "type": "string" + } + }, + "required": [ + "Id", + "Key" + ] + }, + "UploadObjectResponseContent": { + "type": "object", + "properties": { + "Key": { + "type": "string" + }, + "Id": { + "type": "string" + } + }, + "required": [ + "Id", + "Key" + ] + } + } + } +} \ No newline at end of file diff --git a/nswag-spike/package-lock.json b/nswag-spike/package-lock.json new file mode 100644 index 00000000..124ba5f5 --- /dev/null +++ b/nswag-spike/package-lock.json @@ -0,0 +1,44 @@ +{ + "name": "_nswag-spike", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "_nswag-spike", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "js-yaml": "^5.2.1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/js-yaml": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.2.1.tgz", + "integrity": "sha512-zfLtNfQqxVqq3uaTqSkh4x4hZw3KHobGUA0fJUj4wawW8bsQLTVqpHdXSIzidh7o+4lEW36tANuAGdaFx6Zgnw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.mjs" + } + } + } +} diff --git a/nswag-spike/package.json b/nswag-spike/package.json new file mode 100644 index 00000000..1c443e2a --- /dev/null +++ b/nswag-spike/package.json @@ -0,0 +1,16 @@ +{ + "name": "_nswag-spike", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "dependencies": { + "js-yaml": "^5.2.1" + } +} diff --git a/nswag-spike/smithy-pr51/DatabaseService.openapi.json b/nswag-spike/smithy-pr51/DatabaseService.openapi.json new file mode 100644 index 00000000..51263cdd --- /dev/null +++ b/nswag-spike/smithy-pr51/DatabaseService.openapi.json @@ -0,0 +1,741 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Supabase Database API", + "version": "1.0", + "description": "PostgREST-backed database API.\n\nBase URL: https://{project-ref}.supabase.co/rest/v1\n\nKnown limitations:\n 1. Write operations return 204 (no body) by default and 200 with a body when\n Prefer: return=representation \u2014 the model uses 200 throughout so generators\n always produce body-parsing code; clients must tolerate empty bodies.\n 2. RPC GET arguments are function-specific; they are expressed via the same\n @httpQueryParams map as row filters, with function-defined keys." + }, + "paths": { + "/rpc/{functionName}": { + "get": { + "operationId": "CallRpcGet", + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "args", + "in": "query", + "description": "Function arguments \u2014 each entry becomes a query parameter.\nKeys and value formats are defined by the PostgreSQL function signature.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Accept-Profile", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "CallRpcGet 200 response", + "headers": { + "Content-Range": { + "schema": { + "type": "string" + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/CallRpcGetOutputPayload" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "post": { + "operationId": "CallRpcPost", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/CallRpcPostInputPayload" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "Content-Profile", + "in": "header", + "schema": { + "type": "string" + } + }, + { + "name": "Prefer", + "in": "header", + "description": "e.g. \"params=single-object\" \u2014 treat the entire body as a single parameter.", + "schema": { + "type": "string", + "description": "e.g. \"params=single-object\" \u2014 treat the entire body as a single parameter." + } + } + ], + "responses": { + "200": { + "description": "CallRpcPost 200 response", + "headers": { + "Content-Range": { + "schema": { + "type": "string" + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/CallRpcPostOutputPayload" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + } + }, + "/{table}": { + "delete": { + "operationId": "DeleteRows", + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "filters", + "in": "query", + "description": "Horizontal filters \u2014 rows matching these filters will be deleted.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Content-Profile", + "in": "header", + "schema": { + "type": "string" + } + }, + { + "name": "Prefer", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "DeleteRows 200 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/DeleteRowsOutputPayload" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "get": { + "operationId": "SelectRows", + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "description": "Column selection \u2014 comma-separated, supports aliasing, casting, embedded\nresources, and JSON operators. e.g. \"id,name,orders(total,status)\".", + "schema": { + "type": "string", + "description": "Column selection \u2014 comma-separated, supports aliasing, casting, embedded\nresources, and JSON operators. e.g. \"id,name,orders(total,status)\"." + } + }, + { + "name": "order", + "in": "query", + "description": "Ordering \u2014 e.g. \"name.asc,age.desc.nullslast\"", + "schema": { + "type": "string", + "description": "Ordering \u2014 e.g. \"name.asc,age.desc.nullslast\"" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of rows to return.", + "schema": { + "type": "number", + "description": "Maximum number of rows to return." + } + }, + { + "name": "offset", + "in": "query", + "description": "Row offset for pagination.", + "schema": { + "type": "number", + "description": "Row offset for pagination." + } + }, + { + "name": "filters", + "in": "query", + "description": "Horizontal filters \u2014 each entry becomes a query parameter.\nKey: column name (or \"or\"/\"and\" for logical groups).\nValue: \"{operator}.{value}\" e.g. {\"id\": \"eq.5\", \"name\": \"like.foo*\"}.\nSee FilterOperator for the full list of operators.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Accept", + "in": "header", + "description": "Response format. e.g. \"application/json\" (default), \"text/csv\",\n\"application/vnd.pgrst.object+json\" (singular-row mode).", + "schema": { + "type": "string", + "description": "Response format. e.g. \"application/json\" (default), \"text/csv\",\n\"application/vnd.pgrst.object+json\" (singular-row mode)." + } + }, + { + "name": "Accept-Profile", + "in": "header", + "description": "Target a non-default schema exposed by PostgREST.", + "schema": { + "type": "string", + "description": "Target a non-default schema exposed by PostgREST." + } + }, + { + "name": "Prefer", + "in": "header", + "description": "Counting mode. e.g. \"count=exact\", \"count=planned\", \"count=estimated\".", + "schema": { + "type": "string", + "description": "Counting mode. e.g. \"count=exact\", \"count=planned\", \"count=estimated\"." + } + }, + { + "name": "Range", + "in": "header", + "description": "Range-based pagination \u2014 e.g. \"0-9\" (ten rows starting at 0).", + "schema": { + "type": "string", + "description": "Range-based pagination \u2014 e.g. \"0-9\" (ten rows starting at 0)." + } + }, + { + "name": "Range-Unit", + "in": "header", + "description": "Unit for the Range header. Defaults to \"items\".", + "schema": { + "type": "string", + "description": "Unit for the Range header. Defaults to \"items\"." + } + } + ], + "responses": { + "200": { + "description": "SelectRows 200 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/SelectRowsOutputPayload" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "patch": { + "operationId": "UpdateRows", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/UpdateRowsInputPayload" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "filters", + "in": "query", + "description": "Horizontal filters \u2014 rows matching these filters will be updated.\nKey: column name. Value: \"{operator}.{value}\" e.g. {\"id\": \"eq.5\"}.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Content-Profile", + "in": "header", + "schema": { + "type": "string" + } + }, + { + "name": "Prefer", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "UpdateRows 200 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/UpdateRowsOutputPayload" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "post": { + "operationId": "InsertRows", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InsertRowsInputPayload" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "description": "Columns to select in the returned representation (requires return=representation).", + "schema": { + "type": "string", + "description": "Columns to select in the returned representation (requires return=representation)." + } + }, + { + "name": "columns", + "in": "query", + "description": "Restrict which columns may be populated (useful with CSV uploads).", + "schema": { + "type": "string", + "description": "Restrict which columns may be populated (useful with CSV uploads)." + } + }, + { + "name": "Content-Profile", + "in": "header", + "description": "Target a non-default schema for the write.", + "schema": { + "type": "string", + "description": "Target a non-default schema for the write." + } + }, + { + "name": "Prefer", + "in": "header", + "description": "Return behavior and conflict handling.\ne.g. \"return=representation\", \"return=minimal\" (default),\n \"return=headers-only\", \"resolution=merge-duplicates\".", + "schema": { + "type": "string", + "description": "Return behavior and conflict handling.\ne.g. \"return=representation\", \"return=minimal\" (default),\n \"return=headers-only\", \"resolution=merge-duplicates\"." + } + } + ], + "responses": { + "201": { + "description": "InsertRows 201 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InsertRowsOutputPayload" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + }, + "put": { + "operationId": "UpsertRows", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/UpsertRowsInputPayload" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "table", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "select", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "on_conflict", + "in": "query", + "description": "Columns to match for conflict detection (if not the primary key).", + "schema": { + "type": "string", + "description": "Columns to match for conflict detection (if not the primary key)." + } + }, + { + "name": "filters", + "in": "query", + "description": "Horizontal filters \u2014 rows matching these filters will be upserted.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "Content-Profile", + "in": "header", + "schema": { + "type": "string" + } + }, + { + "name": "Prefer", + "in": "header", + "description": "e.g. \"return=representation\", \"resolution=merge-duplicates\",\n \"resolution=ignore-duplicates\".", + "schema": { + "type": "string", + "description": "e.g. \"return=representation\", \"resolution=merge-duplicates\",\n \"resolution=ignore-duplicates\"." + } + } + ], + "responses": { + "200": { + "description": "UpsertRows 200 response", + "headers": { + "Content-Range": { + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count).", + "schema": { + "type": "string", + "description": "Pagination info \u2014 e.g. \"0-9/200\" (range/total) or \"0-9/*\" (unknown count)." + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/UpsertRowsOutputPayload" + } + } + } + }, + "400": { + "description": "DatabaseError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseErrorResponseContent" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "CallRpcGetOutputPayload": { + "type": "string", + "format": "byte" + }, + "CallRpcPostInputPayload": { + "type": "string", + "description": "Named parameters as a JSON object, or a single argument when combined\nwith Prefer: params=single-object.", + "format": "byte" + }, + "CallRpcPostOutputPayload": { + "type": "string", + "format": "byte" + }, + "DatabaseErrorResponseContent": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "PostgreSQL error code (e.g. \"23505\") or PostgREST error code (e.g. \"PGRST301\")." + }, + "message": { + "type": "string", + "description": "Human-readable error message." + }, + "details": { + "type": "string", + "description": "Extra context \u2014 constraint name, offending column, etc." + }, + "hint": { + "type": "string", + "description": "Hint from PostgreSQL." + } + } + }, + "DeleteRowsOutputPayload": { + "type": "string", + "format": "byte" + }, + "InsertRowsInputPayload": { + "type": "string", + "description": "JSON object or array of objects to insert.", + "format": "byte" + }, + "InsertRowsOutputPayload": { + "type": "string", + "format": "byte" + }, + "SelectRowsOutputPayload": { + "type": "string", + "format": "byte" + }, + "StringMap": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Generic string-to-string map \u2014 used for arbitrary query parameter collections\n(e.g. PostgREST filter params, RPC GET arguments)." + }, + "UpdateRowsInputPayload": { + "type": "string", + "description": "Partial JSON object with fields to update.", + "format": "byte" + }, + "UpdateRowsOutputPayload": { + "type": "string", + "format": "byte" + }, + "UpsertRowsInputPayload": { + "type": "string", + "description": "JSON object or array of objects to upsert.", + "format": "byte" + }, + "UpsertRowsOutputPayload": { + "type": "string", + "format": "byte" + }, + "FilterOperator": { + "type": "string", + "description": "PostgREST column filter operators. Format a filter value as \"{operator}.{value}\", e.g. \"eq.5\". Prefix with \"not.\" to negate: \"not.eq.5\". For logical grouping use keys \"or\" / \"and\" in the filters map.", + "enum": [ + "eq", + "neq", + "lt", + "lte", + "gt", + "gte", + "like", + "ilike", + "match", + "imatch", + "is", + "isdistinct", + "in", + "cs", + "cd", + "ov", + "sl", + "sr", + "nxl", + "nxr", + "adj", + "fts", + "plfts", + "phfts", + "wfts" + ] + } + } + } +} \ No newline at end of file diff --git a/nswag-spike/smithy-pr51/FunctionsService.openapi.json b/nswag-spike/smithy-pr51/FunctionsService.openapi.json new file mode 100644 index 00000000..6e8650bd --- /dev/null +++ b/nswag-spike/smithy-pr51/FunctionsService.openapi.json @@ -0,0 +1,357 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Supabase Functions API", + "version": "1.0" + }, + "paths": { + "/functions/v1/{functionName}": { + "delete": { + "operationId": "InvokeFunctionDelete", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InvokeFunctionDeleteInputPayload" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionDelete 200 response", + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InvokeFunctionDeleteOutputPayload" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + }, + "get": { + "operationId": "InvokeFunctionGet", + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionGet 200 response", + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InvokeFunctionGetOutputPayload" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + }, + "patch": { + "operationId": "InvokeFunctionPatch", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InvokeFunctionPatchInputPayload" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionPatch 200 response", + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InvokeFunctionPatchOutputPayload" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + }, + "post": { + "operationId": "InvokeFunctionPost", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InvokeFunctionPostInputPayload" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionPost 200 response", + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InvokeFunctionPostOutputPayload" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + }, + "put": { + "operationId": "InvokeFunctionPut", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InvokeFunctionPutInputPayload" + } + } + } + }, + "parameters": [ + { + "name": "functionName", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "query", + "in": "query", + "description": "Arbitrary query parameters appended to the function URL.\nCorresponds to FunctionInvokeOptions.query.", + "style": "form", + "schema": { + "$ref": "#/components/schemas/StringMap" + } + }, + { + "name": "x-region", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "InvokeFunctionPut 200 response", + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/InvokeFunctionPutOutputPayload" + } + } + } + }, + "400": { + "description": "FunctionsError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionsErrorResponseContent" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "FunctionsErrorResponseContent": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + }, + "InvokeFunctionDeleteInputPayload": { + "type": "string", + "format": "byte" + }, + "InvokeFunctionDeleteOutputPayload": { + "type": "string", + "format": "byte" + }, + "InvokeFunctionGetOutputPayload": { + "type": "string", + "format": "byte" + }, + "InvokeFunctionPatchInputPayload": { + "type": "string", + "format": "byte" + }, + "InvokeFunctionPatchOutputPayload": { + "type": "string", + "format": "byte" + }, + "InvokeFunctionPostInputPayload": { + "type": "string", + "format": "byte" + }, + "InvokeFunctionPostOutputPayload": { + "type": "string", + "format": "byte" + }, + "InvokeFunctionPutInputPayload": { + "type": "string", + "format": "byte" + }, + "InvokeFunctionPutOutputPayload": { + "type": "string", + "format": "byte" + }, + "StringMap": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Generic string-to-string map — used for arbitrary query parameter collections\n(e.g. PostgREST filter params, RPC GET arguments)." + } + } + } +} diff --git a/nswag-spike/smithy-pr51/README.md b/nswag-spike/smithy-pr51/README.md new file mode 100644 index 00000000..6dc30d86 --- /dev/null +++ b/nswag-spike/smithy-pr51/README.md @@ -0,0 +1,115 @@ +# Supabase Smithy Models + +Canonical [Smithy IDL](https://smithy.io/) definitions for the Supabase HTTP APIs. These models are the shared source-of-truth for SDK codegen spikes — each SDK team runs their own generator toolchain against the same models. + +## Structure + +``` +smithy/ + model/ + common.smithy # Shared shapes (StringList, etc.) + storage.smithy # Supabase Storage API (buckets, objects, TUS resumable uploads) + functions.smithy # Supabase Edge Functions API (invoke: GET/POST/PUT/PATCH/DELETE) + database.smithy # Supabase Database API (PostgREST row + RPC operations) + openapi/ + StorageService.openapi.json # Generated OpenAPI 3.0 — committed for SDK consumers + FunctionsService.openapi.json # Generated OpenAPI 3.0 — committed for SDK consumers + DatabaseService.openapi.json # Generated OpenAPI 3.0 — committed for SDK consumers + smithy-build.json # Smithy build config (Smithy CLI / Gradle) + patch-openapi.py # Post-generation patches (see Known Limitations) + README.md +``` + +## Generating the OpenAPI artifacts + +**Requirements:** [Smithy CLI](https://smithy.io/2.0/guides/smithy-cli/cli-installation.html) or Gradle with the Smithy Gradle plugin. + +```bash +cd smithy +smithy build # emits openapi/ into smithy/build/smithy/*/openapi/ +python patch-openapi.py build/smithy/storage-openapi/openapi/StorageService.openapi.json +python patch-openapi.py build/smithy/functions-openapi/openapi/FunctionsService.openapi.json +python patch-openapi.py build/smithy/database-openapi/openapi/DatabaseService.openapi.json +``` + +The committed files in `openapi/` are the patched outputs — SDK teams can consume them directly without installing Smithy. + +## Services modelled + +### Storage (`model/storage.smithy`) + +Covers the full Supabase Storage HTTP API: + +| Group | Operations | +|-------|-----------| +| Buckets | `ListBuckets`, `GetBucket`, `CreateBucket`, `UpdateBucket`, `EmptyBucket`, `DeleteBucket` | +| Objects | `MoveObject`, `CopyObject`, `DeleteObjects`, `ListObjects`, `GetObjectInfo`, `HeadObject` | +| Signed URLs | `CreateSignedUrl`, `CreateSignedUrls`, `CreateSignedUploadUrl` | +| Direct upload | `UploadObject` (POST multipart), `UpdateObject` (PUT multipart) — OpenAPI-only; see Known Limitations | +| TUS resumable | `CreateTusUpload` (POST), `UploadChunk` (PATCH), `GetUploadOffset` (HEAD) | + +### Functions (`model/functions.smithy`) + +Models all five HTTP methods on `/functions/v1/{functionName}`: + +`InvokeFunctionGet`, `InvokeFunctionPost`, `InvokeFunctionPut`, `InvokeFunctionPatch`, `InvokeFunctionDelete` + +Smithy requires one operation per HTTP method — a dispatch switch in the client maps `FunctionInvokeOptions.method` to the right operation at runtime. + +### Database (`model/database.smithy`) + +Covers the PostgREST HTTP API (base URL: `/rest/v1`): + +| Group | Operations | +|-------|-----------| +| Row CRUD | `SelectRows` (GET), `InsertRows` (POST), `UpdateRows` (PATCH), `UpsertRows` (PUT), `DeleteRows` (DELETE) | +| RPC | `CallRpcPost` (POST), `CallRpcGet` (GET) | + +All row operations target `/{table}`. The model captures fixed query params (`select`, `order`, `limit`, `offset`, `on_conflict`, `columns`) and well-known request/response headers (`Prefer`, `Range`, `Range-Unit`, `Accept`, `Accept-Profile`, `Content-Profile`, `Content-Range`). + +Request and response bodies are typed as `Blob` because the row shape is fully dynamic (depends on the table schema). + +Horizontal filter parameters (`?column=op.value`, e.g. `?id=eq.5`) are expressed via an `@httpQueryParams StringMap` member (`filters`) on each read/write input — each map entry becomes a separate query parameter. A `FilterOperator` enum documents all supported operators so they are generated as typed constants in every SDK. RPC GET uses the same pattern (map named `args`) for function-specific query parameters. + +## Known Limitations + +These are gaps found during the Swift spike (see [SDK-1103](https://linear.app/supabase/issue/SDK-1103)) that require workarounds or are out of scope for codegen: + +| # | Gap | Workaround | +|---|-----|-----------| +| 1 | `@streaming blob` emits `format: byte` (base64) in OpenAPI; generators need `format: binary` | `patch-openapi.py` rewrites the format after generation | +| 2 | No native `multipart/form-data` trait in Smithy | `patch-openapi.py` injects `UploadObject`/`UpdateObject` multipart operations directly into the OpenAPI JSON | +| 3 | Smithy requires a fixed HTTP method per operation; Functions supports any method at runtime | Model 5 separate operations; client dispatches at runtime | +| 4 | `GET` + `@httpPayload` is illegal in Smithy | Separate `InvokeFunctionGetInput` shape without a body | +| 5 | Realtime (WebSocket / event-emitter) is incompatible with REST codegen | Out of scope; Realtime stays hand-written in all SDKs | +| 6 | Write operations return 204 (no body) by default and 200 with a body for `return=representation` — Smithy requires a single fixed success code | Model uses 200 throughout; SDK clients must tolerate empty response bodies | + +## Scope for SDK spikes + +The models here cover **Storage**, **Functions**, and **Database (PostgREST)**. Each SDK spike (see Linear issues SDK-1103 through SDK-1109) must also verify **Auth**: + +- **Auth** — sign-in/up, token refresh, OTP, OAuth redirects, session management + +Auth model does not exist yet. It may need to be added here, or the teams may determine that it is unsuitable for codegen (OAuth redirects and cookie-based session management are difficult to express in Smithy). + +For PostgREST the key open question for each SDK spike is whether the transport-layer codegen is useful. The `database.smithy` model covers the full HTTP surface: fixed params (`select`, `order`, `limit`, `offset`), filter params via `@httpQueryParams` + `FilterOperator` enum, and all relevant headers. The only part that stays hand-written is the query-builder API (`.eq()`, `.like()`, etc.) that constructs the filter map — that is by design, not a model gap. + +## Generator toolchains by SDK + +Each SDK team runs their own generator against the OpenAPI artifacts: + +| SDK | Candidate toolchain | +|-----|-------------------| +| Swift | `swift-openapi-generator` (spike done — see [PR #1047](https://github.com/supabase/supabase-swift/pull/1047)) | +| JavaScript/TypeScript | TypeSpec → `@hey-api/openapi-ts` or `@typespec/http-client-js` | +| Python | TypeSpec → `openapi-python-client` or `@typespec/http-client-python` | +| Dart/Flutter | OpenAPI Generator `dart-dio` (no official TypeSpec/Smithy Dart emitter) | +| C# | Kiota or `@typespec/http-client-csharp` | +| Go | `oapi-codegen` or `ogen` | +| Kotlin | `smithy-kotlin` (KMP-compatible) or custom TypeSpec emitter | + +## Reference + +- RFC: [Auto-generating parts of the Supabase SDKs](https://linear.app/supabase/project/rfc-auto-generating-parts-of-the-supabase-sdks-581579f2a632) +- Swift spike PR: [supabase/supabase-swift#1047](https://github.com/supabase/supabase-swift/pull/1047) +- Linear spike issues: SDK-1103 (Swift) · SDK-1104 (JS) · SDK-1105 (Python) · SDK-1106 (Dart) · SDK-1107 (C#) · SDK-1108 (Go) · SDK-1109 (Kotlin) diff --git a/nswag-spike/smithy-pr51/StorageService.openapi.json b/nswag-spike/smithy-pr51/StorageService.openapi.json new file mode 100644 index 00000000..f9a096e7 --- /dev/null +++ b/nswag-spike/smithy-pr51/StorageService.openapi.json @@ -0,0 +1,1401 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Supabase Storage API", + "version": "1.0" + }, + "paths": { + "/bucket": { + "get": { + "operationId": "ListBuckets", + "responses": { + "200": { + "description": "ListBuckets 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListBucketsResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "post": { + "operationId": "CreateBucket", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateBucketRequestContent" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "CreateBucket 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/bucket/{id}": { + "delete": { + "operationId": "DeleteBucket", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "DeleteBucket 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "get": { + "operationId": "GetBucket", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "GetBucket 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetBucketResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "put": { + "operationId": "UpdateBucket", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateBucketRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "UpdateBucket 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/bucket/{id}/empty": { + "post": { + "operationId": "EmptyBucket", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "EmptyBucket 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/copy": { + "post": { + "operationId": "CopyObject", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CopyObjectRequestContent" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "CopyObject 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CopyObjectResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/info/{bucketId}/{wildcardPath+}": { + "get": { + "operationId": "GetObjectInfo", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath+", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "GetObjectInfo 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetObjectInfoResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/list/{bucketId}": { + "post": { + "operationId": "ListObjects", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListObjectsRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "ListObjects 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListObjectsResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/move": { + "post": { + "operationId": "MoveObject", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MoveObjectRequestContent" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "MoveObject 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/sign/{bucketId}": { + "post": { + "operationId": "CreateSignedUrls", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSignedUrlsRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "CreateSignedUrls 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSignedUrlsResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/sign/{bucketId}/{wildcardPath+}": { + "post": { + "operationId": "CreateSignedUrl", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSignedUrlRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath+", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "CreateSignedUrl 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSignedUrlResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/upload/sign/{bucketId}/{wildcardPath+}": { + "post": { + "operationId": "CreateSignedUploadUrl", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath+", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "x-upsert", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "CreateSignedUploadUrl 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSignedUploadUrlResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/{bucketId}": { + "delete": { + "operationId": "DeleteObjects", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteObjectsRequestContent" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "DeleteObjects 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteObjectsResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/object/{bucketId}/{wildcardPath+}": { + "head": { + "operationId": "HeadObject", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath+", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "HeadObject 200 response" + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "post": { + "description": "Upload a new object. Body is multipart/form-data with a required file part.\nSmithy has no native multipart/form-data support; the @httpMultipartForm trait\ndocuments intent and patch-openapi.py injects the correct requestBody schema.", + "operationId": "UploadObject", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath+", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "x-upsert", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "UploadObject 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UploadObjectResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + }, + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "required": [ + "file" + ], + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "cacheControl": { + "type": "string" + }, + "metadata": { + "type": "object" + } + } + } + } + } + } + }, + "put": { + "description": "Replace an existing object. Body is multipart/form-data (see UploadObject).", + "operationId": "UpdateObject", + "parameters": [ + { + "name": "bucketId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "wildcardPath+", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "UpdateObject 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateObjectResponseContent" + } + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + }, + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "required": [ + "file" + ], + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "cacheControl": { + "type": "string" + }, + "metadata": { + "type": "object" + } + } + } + } + } + } + } + }, + "/upload/resumable": { + "post": { + "description": "Step 1: Create a new TUS upload session.\nThe server responds with a Location header containing the upload URL.", + "operationId": "CreateTusUpload", + "parameters": [ + { + "name": "Tus-Resumable", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "Upload-Length", + "in": "header", + "description": "Total size of the file in bytes.", + "schema": { + "type": "number", + "description": "Total size of the file in bytes." + }, + "required": true + }, + { + "name": "Upload-Metadata", + "in": "header", + "description": "Base64-encoded TUS metadata (bucketName, objectName, contentType, cacheControl).", + "schema": { + "type": "string", + "description": "Base64-encoded TUS metadata (bucketName, objectName, contentType, cacheControl)." + }, + "required": true + }, + { + "name": "x-upsert", + "in": "header", + "description": "Set to \"true\" to overwrite an existing object at the same path.", + "schema": { + "type": "string", + "description": "Set to \"true\" to overwrite an existing object at the same path." + } + } + ], + "responses": { + "201": { + "description": "CreateTusUpload 201 response", + "headers": { + "Location": { + "description": "Full URL of the created upload session. Used in subsequent PATCH/HEAD requests.", + "schema": { + "type": "string", + "description": "Full URL of the created upload session. Used in subsequent PATCH/HEAD requests." + }, + "required": true + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + }, + "/upload/resumable/{uploadId}": { + "head": { + "description": "Step 3: Query the server-side offset of a TUS session (used when resuming).", + "operationId": "GetUploadOffset", + "parameters": [ + { + "name": "uploadId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "Tus-Resumable", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "GetUploadOffset 200 response", + "headers": { + "Upload-Offset": { + "schema": { + "type": "number" + }, + "required": true + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + }, + "patch": { + "description": "Step 2: Upload a chunk of data to an existing TUS session.\nRepeat with increasing Upload-Offset until all bytes are sent.", + "operationId": "UploadChunk", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "$ref": "#/components/schemas/UploadChunkInputPayload" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "uploadId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "Tus-Resumable", + "in": "header", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "Upload-Offset", + "in": "header", + "description": "Byte offset at which this chunk begins.", + "schema": { + "type": "number", + "description": "Byte offset at which this chunk begins." + }, + "required": true + } + ], + "responses": { + "204": { + "description": "UploadChunk 204 response", + "headers": { + "Upload-Offset": { + "description": "New server-side offset after the chunk was accepted.", + "schema": { + "type": "number", + "description": "New server-side offset after the chunk was accepted." + }, + "required": true + } + } + }, + "400": { + "description": "StorageError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageErrorResponseContent" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Bucket": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "public": { + "type": "boolean" + }, + "file_size_limit": { + "type": "number" + }, + "allowed_mime_types": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "public" + ] + }, + "CopyObjectRequestContent": { + "type": "object", + "properties": { + "bucketId": { + "type": "string" + }, + "sourceKey": { + "type": "string" + }, + "destinationKey": { + "type": "string" + }, + "destinationBucket": { + "type": "string" + } + }, + "required": [ + "bucketId", + "destinationKey", + "sourceKey" + ] + }, + "CopyObjectResponseContent": { + "type": "object", + "properties": { + "Key": { + "type": "string" + } + }, + "required": [ + "Key" + ] + }, + "CreateBucketRequestContent": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "public": { + "type": "boolean" + }, + "file_size_limit": { + "type": "number" + }, + "allowed_mime_types": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + } + }, + "required": [ + "id", + "name", + "public" + ] + }, + "CreateSignedUploadUrlResponseContent": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + }, + "required": [ + "url" + ] + }, + "CreateSignedUrlRequestContent": { + "type": "object", + "properties": { + "expiresIn": { + "type": "number" + } + }, + "required": [ + "expiresIn" + ] + }, + "CreateSignedUrlResponseContent": { + "type": "object", + "properties": { + "signedURL": { + "type": "string" + } + }, + "required": [ + "signedURL" + ] + }, + "CreateSignedUrlsRequestContent": { + "type": "object", + "properties": { + "expiresIn": { + "type": "number" + }, + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + } + }, + "required": [ + "expiresIn", + "paths" + ] + }, + "CreateSignedUrlsResponseContent": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SignedUrlResult" + } + } + }, + "required": [ + "items" + ] + }, + "DeleteObjectsRequestContent": { + "type": "object", + "properties": { + "prefixes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + } + }, + "required": [ + "prefixes" + ] + }, + "DeleteObjectsResponseContent": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileObject" + } + } + }, + "required": [ + "items" + ] + }, + "FileMetadata": { + "type": "object", + "properties": { + "eTag": { + "type": "string" + }, + "size": { + "type": "number" + }, + "mimetype": { + "type": "string" + }, + "cacheControl": { + "type": "string" + }, + "lastModified": { + "type": "string" + }, + "contentLength": { + "type": "number" + }, + "httpStatusCode": { + "type": "number" + } + } + }, + "FileObject": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "id": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "last_accessed_at": { + "type": "string" + }, + "metadata": { + "$ref": "#/components/schemas/FileMetadata" + } + }, + "required": [ + "name" + ] + }, + "GetBucketResponseContent": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "public": { + "type": "boolean" + }, + "file_size_limit": { + "type": "number" + }, + "allowed_mime_types": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "public" + ] + }, + "GetObjectInfoResponseContent": { + "type": "object", + "properties": { + "eTag": { + "type": "string" + }, + "size": { + "type": "number" + }, + "mimetype": { + "type": "string" + }, + "cacheControl": { + "type": "string" + }, + "lastModified": { + "type": "string" + }, + "contentLength": { + "type": "number" + }, + "httpStatusCode": { + "type": "number" + } + } + }, + "ListBucketsResponseContent": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Bucket" + } + } + }, + "required": [ + "items" + ] + }, + "ListObjectsRequestContent": { + "type": "object", + "properties": { + "prefix": { + "type": "string" + }, + "limit": { + "type": "number" + }, + "offset": { + "type": "number" + }, + "sortBy": { + "$ref": "#/components/schemas/SortBy" + } + }, + "required": [ + "prefix" + ] + }, + "ListObjectsResponseContent": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileObject" + } + } + }, + "required": [ + "items" + ] + }, + "MoveObjectRequestContent": { + "type": "object", + "properties": { + "bucketId": { + "type": "string" + }, + "sourceKey": { + "type": "string" + }, + "destinationKey": { + "type": "string" + }, + "destinationBucket": { + "type": "string" + } + }, + "required": [ + "bucketId", + "destinationKey", + "sourceKey" + ] + }, + "SignedUrlResult": { + "type": "object", + "properties": { + "signedURL": { + "type": "string" + }, + "path": { + "type": "string" + }, + "error": { + "type": "string" + } + }, + "required": [ + "path" + ] + }, + "SortBy": { + "type": "object", + "properties": { + "column": { + "type": "string" + }, + "order": { + "type": "string" + } + } + }, + "StorageErrorResponseContent": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "error": { + "type": "string" + }, + "statusCode": { + "type": "string" + } + } + }, + "UpdateBucketRequestContent": { + "type": "object", + "properties": { + "public": { + "type": "boolean" + }, + "file_size_limit": { + "type": "number" + }, + "allowed_mime_types": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Common string list shape reused across services." + } + }, + "required": [ + "public" + ] + }, + "UpdateObjectResponseContent": { + "type": "object", + "properties": { + "Key": { + "type": "string" + }, + "Id": { + "type": "string" + } + }, + "required": [ + "Id", + "Key" + ] + }, + "UploadChunkInputPayload": { + "type": "string", + "description": "Raw chunk bytes, streamed directly \u2014 never buffered.", + "format": "binary" + }, + "UploadObjectResponseContent": { + "type": "object", + "properties": { + "Key": { + "type": "string" + }, + "Id": { + "type": "string" + } + }, + "required": [ + "Id", + "Key" + ] + } + } + } +} \ No newline at end of file diff --git a/nswag-spike/smithy-pr51/common.smithy b/nswag-spike/smithy-pr51/common.smithy new file mode 100644 index 00000000..93d2ab99 --- /dev/null +++ b/nswag-spike/smithy-pr51/common.smithy @@ -0,0 +1,15 @@ +$version: "2" + +namespace io.supabase + +/// Common string list shape reused across services. +list StringList { + member: String +} + +/// Generic string-to-string map — used for arbitrary query parameter collections +/// (e.g. PostgREST filter params, RPC GET arguments). +map StringMap { + key: String + value: String +} diff --git a/nswag-spike/smithy-pr51/database.smithy b/nswag-spike/smithy-pr51/database.smithy new file mode 100644 index 00000000..b9227d16 --- /dev/null +++ b/nswag-spike/smithy-pr51/database.smithy @@ -0,0 +1,395 @@ +$version: "2" + +namespace io.supabase.database + +use aws.protocols#restJson1 +use io.supabase#StringMap + +/// PostgREST-backed database API. +/// +/// Base URL: https://{project-ref}.supabase.co/rest/v1 +/// +/// Known limitations: +/// 1. Write operations return 204 (no body) by default and 200 with a body when +/// Prefer: return=representation — the model uses 200 throughout so generators +/// always produce body-parsing code; clients must tolerate empty bodies. +/// 2. RPC GET arguments are function-specific; they are expressed via the same +/// @httpQueryParams map as row filters, with function-defined keys. +@restJson1 +@title("Supabase Database API") +service DatabaseService { + version: "1.0" + operations: [ + SelectRows + InsertRows + UpdateRows + UpsertRows + DeleteRows + CallRpcPost + CallRpcGet + ] + errors: [DatabaseError] +} + +// ─── Filter Operators ──────────────────────────────────────────────────────── +// +// PostgREST horizontal filters are expressed as query parameters: +// ?{column}={operator}.{value} e.g. ?id=eq.5&name=like.foo* +// +// Use @httpQueryParams on input structures to pass a StringMap where each entry +// is a column=operator.value pair. Construct values using FilterOperator: +// filters["id"] = FilterOperator.EQ + "." + "5" → ?id=eq.5 +// filters["name"] = FilterOperator.LIKE + "." + "foo*" → ?name=like.foo* +// +// Negation: prefix the operator with "not.": +// filters["id"] = "not.eq.5" → ?id=not.eq.5 +// +// Logical grouping: use the special keys "or" / "and" with a bracketed list: +// filters["or"] = "(id.eq.1,id.eq.2)" → ?or=(id.eq.1,id.eq.2) +// +// Named @httpQuery members (select, order, limit, offset, on_conflict) take +// precedence; do not put those keys in the filters map. + +/// All filter operators supported by PostgREST. +/// Format a filter value as "{operator}.{value}", e.g. FilterOperator.EQ + ".5". +/// Prefix with "not." to negate: "not." + FilterOperator.EQ + ".5". +enum FilterOperator { + /// = (equal) + EQ = "eq" + /// <> (not equal) + NEQ = "neq" + /// < (less than) + LT = "lt" + /// <= (less than or equal) + LTE = "lte" + /// > (greater than) + GT = "gt" + /// >= (greater than or equal) + GTE = "gte" + /// LIKE — case-sensitive pattern match, use * as wildcard + LIKE = "like" + /// ILIKE — case-insensitive pattern match, use * as wildcard + ILIKE = "ilike" + /// ~ — case-sensitive regex match + MATCH = "match" + /// ~* — case-insensitive regex match + IMATCH = "imatch" + /// IS — for null, true, false, unknown + IS = "is" + /// IS DISTINCT FROM + IS_DISTINCT = "isdistinct" + /// IN — value is a parenthesised list: "in.(1,2,3)" + IN = "in" + /// @> (contains — arrays, ranges, jsonb) + CS = "cs" + /// <@ (contained by — arrays, ranges, jsonb) + CD = "cd" + /// && (overlap — arrays, ranges) + OV = "ov" + /// << (strictly left of — ranges) + SL = "sl" + /// >> (strictly right of — ranges) + SR = "sr" + /// &< (does not extend to the left of — ranges) + NXL = "nxl" + /// &> (does not extend to the right of — ranges) + NXR = "nxr" + /// -|- (adjacent — ranges) + ADJ = "adj" + /// @@ to_tsquery (full-text search) + FTS = "fts" + /// @@ plainto_tsquery + PLFTS = "plfts" + /// @@ phraseto_tsquery + PHFTS = "phfts" + /// @@ websearch_to_tsquery + WFTS = "wfts" +} + +// ─── Row Operations ────────────────────────────────────────────────────────── + +@http(method: "GET", uri: "/{table}", code: 200) +@readonly +operation SelectRows { + input: SelectRowsInput + output: RowsOutput + errors: [DatabaseError] +} + +structure SelectRowsInput { + @required + @httpLabel + table: String + + /// Column selection — comma-separated, supports aliasing, casting, embedded + /// resources, and JSON operators. e.g. "id,name,orders(total,status)". + @httpQuery("select") + select: String + + /// Ordering — e.g. "name.asc,age.desc.nullslast" + @httpQuery("order") + order: String + + /// Maximum number of rows to return. + @httpQuery("limit") + limit: Integer + + /// Row offset for pagination. + @httpQuery("offset") + offset: Integer + + /// Counting mode. e.g. "count=exact", "count=planned", "count=estimated". + @httpHeader("Prefer") + prefer: String + + /// Range-based pagination — e.g. "0-9" (ten rows starting at 0). + @httpHeader("Range") + range: String + + /// Unit for the Range header. Defaults to "items". + @httpHeader("Range-Unit") + rangeUnit: String + + /// Response format. e.g. "application/json" (default), "text/csv", + /// "application/vnd.pgrst.object+json" (singular-row mode). + @httpHeader("Accept") + accept: String + + /// Target a non-default schema exposed by PostgREST. + @httpHeader("Accept-Profile") + acceptProfile: String + + /// Horizontal filters — each entry becomes a query parameter. + /// Key: column name (or "or"/"and" for logical groups). + /// Value: "{operator}.{value}" e.g. {"id": "eq.5", "name": "like.foo*"}. + /// See FilterOperator for the full list of operators. + @httpQueryParams + filters: StringMap +} + +structure RowsOutput { + @httpPayload + body: Blob + + /// Pagination info — e.g. "0-9/200" (range/total) or "0-9/*" (unknown count). + @httpHeader("Content-Range") + contentRange: String +} + +@http(method: "POST", uri: "/{table}", code: 201) +operation InsertRows { + input: InsertRowsInput + output: RowsOutput + errors: [DatabaseError] +} + +structure InsertRowsInput { + @required + @httpLabel + table: String + + /// JSON object or array of objects to insert. + @httpPayload + @required + body: Blob + + /// Return behavior and conflict handling. + /// e.g. "return=representation", "return=minimal" (default), + /// "return=headers-only", "resolution=merge-duplicates". + @httpHeader("Prefer") + prefer: String + + /// Columns to select in the returned representation (requires return=representation). + @httpQuery("select") + select: String + + /// Restrict which columns may be populated (useful with CSV uploads). + @httpQuery("columns") + columns: String + + /// Target a non-default schema for the write. + @httpHeader("Content-Profile") + contentProfile: String +} + +@http(method: "PATCH", uri: "/{table}", code: 200) +operation UpdateRows { + input: UpdateRowsInput + output: RowsOutput + errors: [DatabaseError] +} + +structure UpdateRowsInput { + @required + @httpLabel + table: String + + /// Partial JSON object with fields to update. + @httpPayload + @required + body: Blob + + @httpHeader("Prefer") + prefer: String + + @httpQuery("select") + select: String + + @httpHeader("Content-Profile") + contentProfile: String + + /// Horizontal filters — rows matching these filters will be updated. + /// Key: column name. Value: "{operator}.{value}" e.g. {"id": "eq.5"}. + @httpQueryParams + filters: StringMap +} + +@http(method: "PUT", uri: "/{table}", code: 200) +@idempotent +operation UpsertRows { + input: UpsertRowsInput + output: RowsOutput + errors: [DatabaseError] +} + +structure UpsertRowsInput { + @required + @httpLabel + table: String + + /// JSON object or array of objects to upsert. + @httpPayload + @required + body: Blob + + /// e.g. "return=representation", "resolution=merge-duplicates", + /// "resolution=ignore-duplicates". + @httpHeader("Prefer") + prefer: String + + @httpQuery("select") + select: String + + /// Columns to match for conflict detection (if not the primary key). + @httpQuery("on_conflict") + onConflict: String + + @httpHeader("Content-Profile") + contentProfile: String + + /// Horizontal filters — rows matching these filters will be upserted. + @httpQueryParams + filters: StringMap +} + +@http(method: "DELETE", uri: "/{table}", code: 200) +@idempotent +operation DeleteRows { + input: DeleteRowsInput + output: RowsOutput + errors: [DatabaseError] +} + +structure DeleteRowsInput { + @required + @httpLabel + table: String + + @httpHeader("Prefer") + prefer: String + + @httpQuery("select") + select: String + + @httpHeader("Content-Profile") + contentProfile: String + + /// Horizontal filters — rows matching these filters will be deleted. + @httpQueryParams + filters: StringMap +} + +// ─── RPC Operations ────────────────────────────────────────────────────────── +// +// Calls a PostgreSQL function via /rpc/{functionName}. +// POST: function receives named parameters as a JSON object in the body. +// GET: read-only (STABLE/IMMUTABLE) functions only; parameters are query params. +// Argument names are function-specific — pass them via the args map. + +@http(method: "POST", uri: "/rpc/{functionName}", code: 200) +operation CallRpcPost { + input: CallRpcPostInput + output: RpcOutput + errors: [DatabaseError] +} + +structure CallRpcPostInput { + @required + @httpLabel + functionName: String + + /// Named parameters as a JSON object, or a single argument when combined + /// with Prefer: params=single-object. + @httpPayload + body: Blob + + /// e.g. "params=single-object" — treat the entire body as a single parameter. + @httpHeader("Prefer") + prefer: String + + @httpQuery("select") + select: String + + @httpHeader("Content-Profile") + contentProfile: String +} + +@http(method: "GET", uri: "/rpc/{functionName}", code: 200) +@readonly +operation CallRpcGet { + input: CallRpcGetInput + output: RpcOutput + errors: [DatabaseError] +} + +structure CallRpcGetInput { + @required + @httpLabel + functionName: String + + @httpQuery("select") + select: String + + @httpHeader("Accept-Profile") + acceptProfile: String + + /// Function arguments — each entry becomes a query parameter. + /// Keys and value formats are defined by the PostgreSQL function signature. + @httpQueryParams + args: StringMap +} + +structure RpcOutput { + @httpPayload + body: Blob + + @httpHeader("Content-Range") + contentRange: String +} + +// ─── Errors ────────────────────────────────────────────────────────────────── + +@error("client") +structure DatabaseError { + /// PostgreSQL error code (e.g. "23505") or PostgREST error code (e.g. "PGRST301"). + code: String + + /// Human-readable error message. + message: String + + /// Extra context — constraint name, offending column, etc. + details: String + + /// Hint from PostgreSQL. + hint: String +} diff --git a/nswag-spike/smithy-pr51/functions.smithy b/nswag-spike/smithy-pr51/functions.smithy new file mode 100644 index 00000000..bc7a056b --- /dev/null +++ b/nswag-spike/smithy-pr51/functions.smithy @@ -0,0 +1,110 @@ +$version: "2" + +namespace io.supabase.functions + +use aws.protocols#restJson1 +use io.supabase#StringMap + +@restJson1 +@title("Supabase Functions API") +service FunctionsService { + version: "1.0" + operations: [ + InvokeFunctionGet + InvokeFunctionPost + InvokeFunctionPut + InvokeFunctionPatch + InvokeFunctionDelete + ] + errors: [FunctionsError] +} + +// ─── Shared Shapes ───────────────────────────────────────────────────────── + +/// Input for methods that carry a request body (POST, PUT, PATCH, DELETE). +structure InvokeFunctionInput { + @required + @httpLabel + functionName: String + + @httpHeader("x-region") + region: String + + @httpPayload + body: Blob + + /// Arbitrary query parameters appended to the function URL. + /// Corresponds to FunctionInvokeOptions.query. + @httpQueryParams + query: StringMap +} + +/// Input for GET — no body, which GET does not support. +structure InvokeFunctionGetInput { + @required + @httpLabel + functionName: String + + @httpHeader("x-region") + region: String + + /// Arbitrary query parameters appended to the function URL. + /// Corresponds to FunctionInvokeOptions.query. + @httpQueryParams + query: StringMap +} + +structure InvokeFunctionOutput { + @httpPayload + body: Blob +} + +// ─── Operations (one per HTTP method) ────────────────────────────────────── +// +// Smithy requires a fixed HTTP method per operation. We model all five +// methods Supabase Edge Functions accept; FunctionsClient.invoke() dispatches +// to the appropriate generated method based on FunctionInvokeOptions.method. + +@http(method: "GET", uri: "/functions/v1/{functionName}", code: 200) +@readonly +operation InvokeFunctionGet { + input: InvokeFunctionGetInput + output: InvokeFunctionOutput + errors: [FunctionsError] +} + +@http(method: "POST", uri: "/functions/v1/{functionName}", code: 200) +operation InvokeFunctionPost { + input: InvokeFunctionInput + output: InvokeFunctionOutput + errors: [FunctionsError] +} + +@http(method: "PUT", uri: "/functions/v1/{functionName}", code: 200) +@idempotent +operation InvokeFunctionPut { + input: InvokeFunctionInput + output: InvokeFunctionOutput + errors: [FunctionsError] +} + +@http(method: "PATCH", uri: "/functions/v1/{functionName}", code: 200) +operation InvokeFunctionPatch { + input: InvokeFunctionInput + output: InvokeFunctionOutput + errors: [FunctionsError] +} + +@http(method: "DELETE", uri: "/functions/v1/{functionName}", code: 200) +@idempotent +@suppress(["HttpMethodSemantics.UnexpectedPayload"]) +operation InvokeFunctionDelete { + input: InvokeFunctionInput + output: InvokeFunctionOutput + errors: [FunctionsError] +} + +@error("client") +structure FunctionsError { + message: String +} diff --git a/nswag-spike/smithy-pr51/patch-openapi.py b/nswag-spike/smithy-pr51/patch-openapi.py new file mode 100644 index 00000000..5449fc4c --- /dev/null +++ b/nswag-spike/smithy-pr51/patch-openapi.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +""" +Post-process the Smithy-generated OpenAPI JSON with patches that Smithy +cannot express natively. + +Storage patches: + 1. UploadObject / UpdateObject requestBody: inject multipart/form-data schema. + Smithy has no native multipart/form-data support. The @httpMultipartForm + trait in the model documents intent; this script performs the actual injection. + 2. UploadChunk body: format: byte → format: binary. + (@streaming blob translates to format:byte but swift-openapi-generator + needs format:binary to emit HTTPBody instead of Base64EncodedData) + +Database patches: + 3. FilterOperator enum — defined in Smithy but not referenced as a member + type (filter map values are raw strings), so it is absent from the + generated output. Injected here so OpenAPI-based generators emit it. +""" +import json +import sys + +path = sys.argv[1] if len(sys.argv) > 1 else "output/openapi/StorageService.openapi.json" + +with open(path) as f: + d = json.load(f) + +service_title = d.get("info", {}).get("title", "") + +# ── Patch 3: FilterOperator enum (DatabaseService only) ─────────────────── +if service_title == "Supabase Database API": + d["components"]["schemas"]["FilterOperator"] = { + "type": "string", + "description": ( + "PostgREST column filter operators. " + "Format a filter value as \"{operator}.{value}\", e.g. \"eq.5\". " + "Prefix with \"not.\" to negate: \"not.eq.5\". " + "For logical grouping use keys \"or\" / \"and\" in the filters map." + ), + "enum": [ + "eq", "neq", "lt", "lte", "gt", "gte", + "like", "ilike", "match", "imatch", + "is", "isdistinct", "in", + "cs", "cd", "ov", + "sl", "sr", "nxl", "nxr", "adj", + "fts", "plfts", "phfts", "wfts", + ], + } + with open(path, "w") as f: + json.dump(d, f, indent=4) + print(f"Patched (database): {path}") + sys.exit(0) + +# ── Patch 1: multipart/form-data for UploadObject and UpdateObject ──────── +MULTIPART_BODY = { + "required": True, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "required": ["file"], + "properties": { + "file": {"type": "string", "format": "binary"}, + "cacheControl": {"type": "string"}, + "metadata": {"type": "object"}, + }, + } + } + }, +} + +upload_path = "/object/{bucketId}/{wildcardPath+}" +if upload_path in d.get("paths", {}): + for method in ("post", "put"): + if method in d["paths"][upload_path]: + d["paths"][upload_path][method]["requestBody"] = MULTIPART_BODY + +# ── Patch 2: streaming blob → binary ────────────────────────────────────── +schema = d["components"]["schemas"].get("UploadChunkInputPayload", {}) +if schema.get("format") == "byte": + schema["format"] = "binary" + +with open(path, "w") as f: + json.dump(d, f, indent=2) + +print(f"Patched (storage): {path}") diff --git a/nswag-spike/smithy-pr51/storage.smithy b/nswag-spike/smithy-pr51/storage.smithy new file mode 100644 index 00000000..a85ce9c1 --- /dev/null +++ b/nswag-spike/smithy-pr51/storage.smithy @@ -0,0 +1,498 @@ +$version: "2" + +namespace io.supabase.storage + +use aws.protocols#restJson1 +use io.supabase#StringList +use io.supabase.traits#httpMultipartForm + +@restJson1 +@title("Supabase Storage API") +service StorageService { + version: "1.0" + operations: [ + ListBuckets + GetBucket + CreateBucket + UpdateBucket + EmptyBucket + DeleteBucket + MoveObject + CopyObject + DeleteObjects + ListObjects + GetObjectInfo + HeadObject + CreateSignedUrl + CreateSignedUrls + CreateSignedUploadUrl + UploadObject + UpdateObject + CreateTusUpload + UploadChunk + GetUploadOffset + ] + errors: [StorageError] +} + +// ─── Bucket Operations ───────────────────────────────────────────────────── + +@http(method: "GET", uri: "/bucket", code: 200) +@readonly +operation ListBuckets { + output: ListBucketsOutput + errors: [StorageError] +} + +structure ListBucketsOutput { + @required + items: BucketList +} + +list BucketList { + member: Bucket +} + +@http(method: "GET", uri: "/bucket/{id}", code: 200) +@readonly +operation GetBucket { + input: GetBucketInput + output: Bucket + errors: [StorageError] +} + +structure GetBucketInput { + @required + @httpLabel + id: String +} + +@http(method: "POST", uri: "/bucket", code: 200) +operation CreateBucket { + input: CreateBucketInput + errors: [StorageError] +} + +structure CreateBucketInput { + @required id: String + @required name: String + @required @jsonName("public") isPublic: Boolean + file_size_limit: Long + allowed_mime_types: StringList +} + +@http(method: "PUT", uri: "/bucket/{id}", code: 200) +@idempotent +operation UpdateBucket { + input: UpdateBucketInput + errors: [StorageError] +} + +structure UpdateBucketInput { + @required + @httpLabel + id: String + + @required @jsonName("public") isPublic: Boolean + file_size_limit: Long + allowed_mime_types: StringList +} + +@http(method: "POST", uri: "/bucket/{id}/empty", code: 200) +operation EmptyBucket { + input: EmptyBucketInput + errors: [StorageError] +} + +structure EmptyBucketInput { + @required + @httpLabel + id: String +} + +@http(method: "DELETE", uri: "/bucket/{id}", code: 200) +@idempotent +operation DeleteBucket { + input: DeleteBucketInput + errors: [StorageError] +} + +structure DeleteBucketInput { + @required + @httpLabel + id: String +} + +// ─── Object Operations ───────────────────────────────────────────────────── + +@http(method: "POST", uri: "/object/move", code: 200) +operation MoveObject { + input: MoveObjectInput + errors: [StorageError] +} + +structure MoveObjectInput { + @required bucketId: String + @required sourceKey: String + @required destinationKey: String + destinationBucket: String +} + +@http(method: "POST", uri: "/object/copy", code: 200) +operation CopyObject { + input: CopyObjectInput + output: CopyObjectOutput + errors: [StorageError] +} + +structure CopyObjectInput { + @required bucketId: String + @required sourceKey: String + @required destinationKey: String + destinationBucket: String +} + +structure CopyObjectOutput { + @required Key: String +} + +@http(method: "DELETE", uri: "/object/{bucketId}", code: 200) +@idempotent +@suppress(["HttpMethodSemantics.UnexpectedPayload"]) +operation DeleteObjects { + input: DeleteObjectsInput + output: DeleteObjectsOutput + errors: [StorageError] +} + +structure DeleteObjectsInput { + @required + @httpLabel + bucketId: String + + @required prefixes: StringList +} + +structure DeleteObjectsOutput { + @required + items: FileObjectList +} + +list FileObjectList { + member: FileObject +} + +@http(method: "POST", uri: "/object/list/{bucketId}", code: 200) +operation ListObjects { + input: ListObjectsInput + output: ListObjectsOutput + errors: [StorageError] +} + +structure ListObjectsInput { + @required + @httpLabel + bucketId: String + + @required prefix: String + limit: Integer + offset: Integer + sortBy: SortBy +} + +structure SortBy { + column: String + order: String +} + +structure ListObjectsOutput { + @required + items: FileObjectList +} + +@http(method: "GET", uri: "/object/info/{bucketId}/{wildcardPath+}", code: 200) +@readonly +operation GetObjectInfo { + input: GetObjectInfoInput + output: FileInfo + errors: [StorageError] +} + +structure GetObjectInfoInput { + @required @httpLabel bucketId: String + @required @httpLabel wildcardPath: String +} + +@http(method: "HEAD", uri: "/object/{bucketId}/{wildcardPath+}", code: 200) +@readonly +operation HeadObject { + input: HeadObjectInput + errors: [StorageError] +} + +structure HeadObjectInput { + @required @httpLabel bucketId: String + @required @httpLabel wildcardPath: String +} + +/// Upload a new object. Body is multipart/form-data with a required file part. +/// Smithy has no native multipart/form-data support; the @httpMultipartForm trait +/// documents intent and patch-openapi.py injects the correct requestBody schema. +@http(method: "POST", uri: "/object/{bucketId}/{wildcardPath+}", code: 200) +operation UploadObject { + input: UploadObjectInput + output: FileUploadedResponse + errors: [StorageError] +} + +@httpMultipartForm(fields: [ + {name: "file", fieldType: "binary", required: true}, + {name: "cacheControl", fieldType: "string", required: false}, + {name: "metadata", fieldType: "object", required: false} +]) +structure UploadObjectInput { + @required @httpLabel bucketId: String + @required @httpLabel wildcardPath: String + @httpHeader("x-upsert") upsert: String +} + +/// Replace an existing object. Body is multipart/form-data (see UploadObject). +@http(method: "PUT", uri: "/object/{bucketId}/{wildcardPath+}", code: 200) +@idempotent +operation UpdateObject { + input: UpdateObjectInput + output: FileUploadedResponse + errors: [StorageError] +} + +@httpMultipartForm(fields: [ + {name: "file", fieldType: "binary", required: true}, + {name: "cacheControl", fieldType: "string", required: false}, + {name: "metadata", fieldType: "object", required: false} +]) +structure UpdateObjectInput { + @required @httpLabel bucketId: String + @required @httpLabel wildcardPath: String +} + +structure FileUploadedResponse { + @required @jsonName("Key") key: String + @required @jsonName("Id") id: String +} + +@http(method: "POST", uri: "/object/sign/{bucketId}/{wildcardPath+}", code: 200) +operation CreateSignedUrl { + input: CreateSignedUrlInput + output: CreateSignedUrlOutput + errors: [StorageError] +} + +structure CreateSignedUrlInput { + @required @httpLabel bucketId: String + @required @httpLabel wildcardPath: String + @required expiresIn: Integer +} + +structure CreateSignedUrlOutput { + @required signedURL: String +} + +@http(method: "POST", uri: "/object/sign/{bucketId}", code: 200) +operation CreateSignedUrls { + input: CreateSignedUrlsInput + output: CreateSignedUrlsOutput + errors: [StorageError] +} + +structure CreateSignedUrlsInput { + @required @httpLabel bucketId: String + @required expiresIn: Integer + @required paths: StringList +} + +structure CreateSignedUrlsOutput { + @required + items: SignedUrlResultList +} + +list SignedUrlResultList { + member: SignedUrlResult +} + +structure SignedUrlResult { + signedURL: String + @required path: String + error: String +} + +@http(method: "POST", uri: "/object/upload/sign/{bucketId}/{wildcardPath+}", code: 200) +operation CreateSignedUploadUrl { + input: CreateSignedUploadUrlInput + output: CreateSignedUploadUrlOutput + errors: [StorageError] +} + +structure CreateSignedUploadUrlInput { + @required @httpLabel bucketId: String + @required @httpLabel wildcardPath: String + @httpHeader("x-upsert") upsert: String +} + +structure CreateSignedUploadUrlOutput { + @required url: String +} + +// ─── TUS Resumable Upload Operations ─────────────────────────────────────── +// +// Models the three HTTP operations of the TUS 1.0.0 protocol. The application- +// level state machine (chunk sequencing, 409 retry, pause/resume) is NOT +// generated — it lives in TUSUploadEngine, which calls these operations. + +/// Step 1: Create a new TUS upload session. +/// The server responds with a Location header containing the upload URL. +@http(method: "POST", uri: "/upload/resumable", code: 201) +operation CreateTusUpload { + input: CreateTusUploadInput + output: CreateTusUploadOutput + errors: [StorageError] +} + +structure CreateTusUploadInput { + /// Total size of the file in bytes. + @httpHeader("Upload-Length") + @required + uploadLength: Long + + /// Base64-encoded TUS metadata (bucketName, objectName, contentType, cacheControl). + @httpHeader("Upload-Metadata") + @required + uploadMetadata: String + + @httpHeader("Tus-Resumable") + @required + tusResumable: String + + /// Set to "true" to overwrite an existing object at the same path. + @httpHeader("x-upsert") + upsert: String +} + +structure CreateTusUploadOutput { + /// Full URL of the created upload session. Used in subsequent PATCH/HEAD requests. + @httpHeader("Location") + @required + location: String +} + +/// Step 2: Upload a chunk of data to an existing TUS session. +/// Repeat with increasing Upload-Offset until all bytes are sent. +@http(method: "PATCH", uri: "/upload/resumable/{uploadId}", code: 204) +@suppress(["HttpMethodSemantics.UnexpectedPayload"]) +operation UploadChunk { + input: UploadChunkInput + output: UploadChunkOutput + errors: [StorageError] +} + +@streaming +blob ChunkBody + +structure UploadChunkInput { + @httpLabel + @required + uploadId: String + + /// Byte offset at which this chunk begins. + @httpHeader("Upload-Offset") + @required + uploadOffset: Long + + @httpHeader("Tus-Resumable") + @required + tusResumable: String + + /// Raw chunk bytes, streamed directly — never buffered. + @httpPayload + @required + body: ChunkBody +} + +structure UploadChunkOutput { + /// New server-side offset after the chunk was accepted. + @httpHeader("Upload-Offset") + @required + uploadOffset: Long +} + +/// Step 3: Query the server-side offset of a TUS session (used when resuming). +@http(method: "HEAD", uri: "/upload/resumable/{uploadId}", code: 200) +@readonly +operation GetUploadOffset { + input: GetUploadOffsetInput + output: GetUploadOffsetOutput + errors: [StorageError] +} + +structure GetUploadOffsetInput { + @httpLabel + @required + uploadId: String + + @httpHeader("Tus-Resumable") + @required + tusResumable: String +} + +structure GetUploadOffsetOutput { + @httpHeader("Upload-Offset") + @required + uploadOffset: Long +} + +// ─── Shared Shapes ───────────────────────────────────────────────────────── + +structure Bucket { + @required id: String + @required name: String + @required @jsonName("public") isPublic: Boolean + file_size_limit: Long + allowed_mime_types: StringList + created_at: String + updated_at: String +} + +structure FileObject { + @required name: String + id: String + updated_at: String + created_at: String + last_accessed_at: String + metadata: FileMetadata +} + +structure FileMetadata { + eTag: String + size: Long + mimetype: String + cacheControl: String + lastModified: String + contentLength: Long + httpStatusCode: Integer +} + +structure FileInfo { + eTag: String + size: Long + mimetype: String + cacheControl: String + lastModified: String + contentLength: Long + httpStatusCode: Integer +} + +@error("client") +structure StorageError { + message: String + error: String + statusCode: String +} diff --git a/nswag-spike/spike-nswag.csproj b/nswag-spike/spike-nswag.csproj new file mode 100644 index 00000000..ce271026 --- /dev/null +++ b/nswag-spike/spike-nswag.csproj @@ -0,0 +1,45 @@ + + + + + netstandard2.1 + enable + latest + false + false + + + false + false + false + $(NoWarn);CS1591 + + false + false + + + + + + + + + + + + + + + + + + + + + + diff --git a/nswag-testrun/Program.cs b/nswag-testrun/Program.cs new file mode 100644 index 00000000..bf5cfcf4 --- /dev/null +++ b/nswag-testrun/Program.cs @@ -0,0 +1,109 @@ +// Manual test-run for the NSwag-generated Supabase Storage client (SDK-1107). +// Mirror of ../kiota-testrun — same steps, same local platform — for a like-for-like comparison. +// +// Verifies against a LOCAL Supabase platform: +// • HttpClient injection — the NSwag client takes an external HttpClient in its constructor +// • real round-trip — ListBuckets / CreateBucket against the live Storage API +// • streaming upload — UploadObject from a FileStream via FileParameter/StreamContent +// +// Run: +// supabase start ; supabase status # copy service_role key + API URL +// SUPABASE_URL=http://127.0.0.1:54321 SUPABASE_KEY= dotnet run + +using Supabase.Storage.Gen; + +var supabaseUrl = Environment.GetEnvironmentVariable("SUPABASE_URL") ?? "http://127.0.0.1:54321"; +var supabaseKey = Environment.GetEnvironmentVariable("SUPABASE_KEY") + ?? "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU"; + +Console.WriteLine($"Supabase URL : {supabaseUrl}"); +Console.WriteLine($"Storage base : {supabaseUrl}/storage/v1"); +Console.WriteLine($"Key : {supabaseKey[..12]}…\n"); + +// ── HttpClient injection ──────────────────────────────────────────────────── +// NSwag client ctor takes an external HttpClient. Base address carries /storage/v1/ (the generated +// client builds relative URIs); auth headers go on the client (DI / IHttpClientFactory shape). +var http = new HttpClient { BaseAddress = new Uri($"{supabaseUrl}/storage/v1/") }; +http.DefaultRequestHeaders.Add("apikey", supabaseKey); +http.DefaultRequestHeaders.Add("Authorization", $"Bearer {supabaseKey}"); + +var client = new StorageClient(http); +Console.WriteLine("[✓] HttpClient injection — client built over an external HttpClient\n"); + +var bucketId = $"nswag-spike-{DateTime.UtcNow:yyyyMMddHHmmss}"; +var pass = 0; +var fail = 0; + +async Task Step(string name, Func action) +{ + try { await action(); Console.WriteLine($"[✓] {name}\n"); pass++; } + catch (Exception ex) { Console.WriteLine($"[✗] {name}\n {ex.GetType().Name}: {ex.Message}\n"); fail++; } +} + +// ── round-trip: list buckets ──────────────────────────────────────────────── +await Step("ListBuckets", async () => +{ + // Envelope fix: the response is a bare array; the generated client now returns + // ICollection directly (previously ListBucketsResponseContent.Items, which + // never matched the wire shape and threw on deserialize). + var buckets = await client.ListBucketsAsync(); + Console.WriteLine($" server returned {buckets?.Count ?? 0} bucket(s)"); +}); + +// ── round-trip: create bucket ─────────────────────────────────────────────── +await Step($"CreateBucket ({bucketId})", async () => +{ + // Nullable fix: File_size_limit is now `double?` (was non-nullable `double` defaulting to 0, + // which created buckets that rejected every upload with 413). NSwag still serializes null + // for unset properties (no WhenWritingNull), so this first attempt sends file_size_limit:null — + // whether the server treats null as unset is exactly what this step measures. + try + { + await client.CreateBucketAsync(new CreateBucketRequestContent + { + Id = bucketId, Name = bucketId, Public = false // File_size_limit deliberately unset + }); + Console.WriteLine(" created WITHOUT File_size_limit (server accepted null as unset)"); + } + catch (ApiException ex) + { + Console.WriteLine($" server rejected file_size_limit:null ({ex.StatusCode}) → WhenWritingNull still required client-side; retrying with explicit value"); + await client.CreateBucketAsync(new CreateBucketRequestContent + { + Id = bucketId, Name = bucketId, Public = false, File_size_limit = 52428800 /* 50 MB */ + }); + Console.WriteLine(" created with explicit File_size_limit"); + } +}); + +// ── streaming upload: FileStream → FileParameter/StreamContent (no byte[] buffering) ── +var objectName = "hello.txt"; +await Step($"UploadObject (streaming FileStream → {bucketId}/{objectName})", async () => +{ + var tmp = Path.GetTempFileName(); + await File.WriteAllTextAsync(tmp, $"streamed from NSwag test-run at {DateTime.UtcNow:O}\n"); + var sizeKb = new FileInfo(tmp).Length / 1024.0; + + await using var fileStream = File.OpenRead(tmp); // <-- streamed, not buffered + var file = new FileParameter(fileStream, objectName, "text/plain"); + + var resp = await client.UploadObjectAsync(bucketId, objectName, x_upsert: "true", + file: file, cacheControl: "3600", metadata: new { }); + Console.WriteLine($" uploaded {sizeKb:0.00} KB via StreamContent; key = {resp?.Key ?? "(none)"}"); + File.Delete(tmp); +}); + +// ── confirm the object landed ─────────────────────────────────────────────── +await Step("ListObjects (confirm upload)", async () => +{ + // Nullable fix: Limit/Offset are now double? (were non-nullable, defaulting to 0 → 400 + // "limit must be >= 1"). NSwag still writes null for unset members (no WhenWritingNull), + // so unset fields go as explicit nulls (limit:null / sortBy:null) — this step measures + // whether the server tolerates that. Envelope fix: returns ICollection directly. + var listed = await client.ListObjectsAsync(new ListObjectsRequestContent { Prefix = "" }, bucketId); + Console.WriteLine($" bucket now holds {listed?.Count ?? 0} object(s)"); +}); + +Console.WriteLine(new string('─', 60)); +Console.WriteLine($"Result: {pass} passed, {fail} failed"); +return fail == 0 ? 0 : 1; diff --git a/nswag-testrun/README.md b/nswag-testrun/README.md new file mode 100644 index 00000000..5e436429 --- /dev/null +++ b/nswag-testrun/README.md @@ -0,0 +1,43 @@ +# spike-nswag.TestRun — manual run of the NSwag client vs local Supabase + +Hand-written (ownable) console harness that drives the **NSwag-generated Storage client** +(`../nswag-spike`) against a **local Supabase platform**. Mirror of `../kiota-testrun` for a +like-for-like comparison. + +## What it verifies + +Same steps as the Kiota harness: HttpClient injection, ListBuckets / CreateBucket round-trip, +streaming upload (FileStream → `FileParameter`/`StreamContent`), ListObjects. + +## Run + +```bash +supabase start ; supabase status # copy the API URL + service_role key +SUPABASE_URL=http://127.0.0.1:54321 SUPABASE_KEY= dotnet run +``` + +## Status — executed ✅ (2 passed / 2 failed — and the failures are the finding) + +| Step | Result | Why | +|------|--------|-----| +| HttpClient injection | ✅ | client built over an external `HttpClient` | +| ListBuckets | ❌ | **model envelope bug** — API returns a bare array, model expects `{items:[]}` → NSwag **throws** `ApiException` (Kiota silently returned 0) | +| CreateBucket | ✅* | *only after working around the next bug | +| **UploadObject (streaming)** | ✅ | FileStream streamed via `StreamContent` — object confirmed on server | +| ListObjects | ❌ | NSwag serializes `sortBy:null` / `limit:0` → server 400s | + +**Two NSwag bugs the run exposed (static analysis missed both):** + +1. **NSwag emits every optional field at its default and serializes it** (no `WhenWritingNull`): + `file_size_limit:0`, `limit:0`, `offset:0`, `sortBy:null`. The server rejects several — + `file_size_limit:0` creates a bucket that **413s every upload**; `limit:0` → *"must be >= 1"*; + `sortBy:null` → *"must be object"*. Optional value types are non-nullable and always sent. + **Kiota omits unset fields → its calls just worked.** So NSwag's request DTOs are **not usable + as-is** against Supabase without a serialization fix (`DefaultIgnoreCondition = WhenWritingNull` + + nullable value types, or nullable annotations upstream). +2. **Shared list-envelope model bug** (same as Kiota) — but NSwag **throws** where Kiota silently + returned empty. Loud-fail is arguably the safer behaviour. + +See `../nswag-spike/evaluation-nswag.md` (Live run section) and the root `../codegen-comparison.md`. + +> Isolated spike project: in `Supabase.sln`, **not referenced by `Supabase.csproj`**. diff --git a/nswag-testrun/spike-nswag.TestRun.csproj b/nswag-testrun/spike-nswag.TestRun.csproj new file mode 100644 index 00000000..3b507550 --- /dev/null +++ b/nswag-testrun/spike-nswag.TestRun.csproj @@ -0,0 +1,23 @@ + + + + + Exe + net8.0 + enable + enable + Supabase.Spike.NSwagTestRun + false + + + + + + + +