diff --git a/cmd/snippets.go b/cmd/snippets.go index f69b232af..1bf25129a 100644 --- a/cmd/snippets.go +++ b/cmd/snippets.go @@ -5,6 +5,7 @@ import ( "github.com/spf13/cobra" "github.com/supabase/cli/internal/snippets/download" "github.com/supabase/cli/internal/snippets/list" + "github.com/supabase/cli/internal/snippets/push" "github.com/supabase/cli/internal/utils/flags" ) @@ -25,19 +26,33 @@ var ( } snippetsDownloadCmd = &cobra.Command{ - Use: "download ", - Short: "Download contents of a SQL snippet", - Long: "Download contents of the specified SQL snippet.", - Args: cobra.ExactArgs(1), + Use: "download [snippet-id]", + Short: "Download one or all SQL snippets", + Long: "Download the contents of the specified SQL snippet if an ID is provided. If no ID is supplied, download all snippets into the local project directory.", + Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return download.Run(cmd.Context(), args[0], afero.NewOsFs()) + var snippetId string + if len(args) > 0 { + snippetId = args[0] + } + return download.Run(cmd.Context(), snippetId, afero.NewOsFs()) }, } + + snippetsPushCmd = &cobra.Command{ + Use: "push", + Short: "Push local SQL snippets to Supabase", + Long: "Create or update SQL snippets from the local supabase/snippets directory to the linked project.", + RunE: func(cmd *cobra.Command, args []string) error { + return push.Run(cmd.Context(), afero.NewOsFs()) + }, + } ) func init() { snippetsCmd.PersistentFlags().StringVar(&flags.ProjectRef, "project-ref", "", "Project ref of the Supabase project.") snippetsCmd.AddCommand(snippetsListCmd) snippetsCmd.AddCommand(snippetsDownloadCmd) + snippetsCmd.AddCommand(snippetsPushCmd) rootCmd.AddCommand(snippetsCmd) } diff --git a/cmd/test.go b/cmd/test.go index 06fb77730..28b409445 100644 --- a/cmd/test.go +++ b/cmd/test.go @@ -7,12 +7,15 @@ import ( "github.com/spf13/afero" "github.com/spf13/cobra" "github.com/supabase/cli/internal/test/new" + testsDownload "github.com/supabase/cli/internal/tests/download" + testsPush "github.com/supabase/cli/internal/tests/push" "github.com/supabase/cli/internal/utils" + "github.com/supabase/cli/internal/utils/flags" ) var ( testCmd = &cobra.Command{ - GroupID: groupLocalDev, + GroupID: groupManagementAPI, Use: "test", Short: "Run tests on local Supabase containers", } @@ -37,6 +40,25 @@ var ( return new.Run(ctx, args[0], template.Value, afero.NewOsFs()) }, } + + testDownloadCmd = &cobra.Command{ + Use: "download [test-id]", + Short: "Download one or all SQL tests", + Args: cobra.MaximumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + var id string + if len(args) > 0 { id = args[0] } + return testsDownload.Run(cmd.Context(), id, afero.NewOsFs()) + }, + } + + testPushCmd = &cobra.Command{ + Use: "push", + Short: "Push local SQL tests to Supabase", + RunE: func(cmd *cobra.Command, args []string) error { + return testsPush.Run(cmd.Context(), afero.NewOsFs()) + }, + } ) func init() { @@ -51,6 +73,10 @@ func init() { newFlags := testNewCmd.Flags() newFlags.VarP(&template, "template", "t", "Template framework to generate.") testCmd.AddCommand(testNewCmd) + // Build download and push commands + testCmd.PersistentFlags().StringVar(&flags.ProjectRef, "project-ref", "", "Project ref of the Supabase project.") + testCmd.AddCommand(testDownloadCmd) + testCmd.AddCommand(testPushCmd) // Build test command rootCmd.AddCommand(testCmd) } diff --git a/internal/content/content.go b/internal/content/content.go new file mode 100644 index 000000000..c6d6525a5 --- /dev/null +++ b/internal/content/content.go @@ -0,0 +1,400 @@ +package content + +import ( + "context" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/go-errors/errors" + "github.com/google/uuid" + "github.com/spf13/afero" + "github.com/supabase/cli/internal/utils" + "github.com/supabase/cli/internal/utils/flags" + "github.com/supabase/cli/pkg/api" +) + +const schemaVersion = "1" + +type ContentType api.UpsertContentBodyType + +const ( + ContentTypeTest ContentType = ContentType(api.UpsertContentBodyTypeTest) + ContentTypeSnippet ContentType = ContentType(api.UpsertContentBodyTypeSql) +) + +type Config struct { + Type ContentType + Directory string + DisplayName string +} + +func GetConfig(contentType ContentType) Config { + switch contentType { + case ContentTypeTest: + return Config{ + Type: ContentTypeTest, + Directory: utils.TestsDir, + DisplayName: "test", + } + case ContentTypeSnippet: + return Config{ + Type: ContentTypeSnippet, + Directory: utils.SnippetsDir, + DisplayName: "snippet", + } + default: + panic("unsupported content type") + } +} + +func Push(ctx context.Context, fsys afero.Fs, contentType ContentType) error { + if err := flags.LoadConfig(fsys); err != nil { + return err + } + + config := GetConfig(contentType) + + exists, err := afero.DirExists(fsys, config.Directory) + if err != nil || !exists { + return errors.Errorf("%s does not exist", config.Directory) + } + + entries, err := afero.ReadDir(fsys, config.Directory) + if err != nil { + return err + } + + locals := map[string]string{} + for _, e := range entries { + if e.IsDir() || !strings.HasSuffix(e.Name(), ".sql") { + continue + } + name := strings.TrimSuffix(e.Name(), ".sql") + bytes, _ := afero.ReadFile(fsys, filepath.Join(config.Directory, e.Name())) + locals[name] = string(bytes) + } + + if len(locals) == 0 { + fmt.Printf("No %s files found to push\n", config.DisplayName) + return nil + } + + remote, err := listRemote(ctx, contentType) + if err != nil { + return err + } + + for name, sql := range locals { + if id, ok := remote[name]; ok { + if err := upsert(ctx, contentType, id, name, sql); err != nil { + fmt.Fprintf(utils.GetDebugLogger(), "failed to update %s %s: %v\n", config.DisplayName, name, err) + } else { + fmt.Printf("Updated %s %s\n", config.DisplayName, utils.Aqua(name)) + } + } else { + if err := create(ctx, contentType, name, sql); err != nil { + fmt.Fprintf(utils.GetDebugLogger(), "failed to create %s %s: %v\n", config.DisplayName, name, err) + } else { + fmt.Printf("Created %s %s\n", config.DisplayName, utils.Aqua(name)) + } + } + } + + var deletions []uuid.UUID + var deletionNames []string + for name, id := range remote { + if _, ok := locals[name]; !ok { + deletions = append(deletions, id) + deletionNames = append(deletionNames, name) + } + } + + if len(deletions) > 0 { + console := utils.NewConsole() + msg := fmt.Sprintf("Your remote project has %d %s(s) that don't exist locally:\n %s\nDo you want to delete them from the remote project?", + len(deletions), config.DisplayName, strings.Join(deletionNames, "\n ")) + shouldDelete, err := console.PromptYesNo(ctx, msg, false) + if err != nil { + return err + } + if shouldDelete { + for _, id := range deletions { + utils.GetSupabase().V1ProjectDeleteSnippet(ctx, flags.ProjectRef, id) + } + fmt.Printf("Deleted %d obsolete %ss\n", len(deletions), config.DisplayName) + } else { + fmt.Printf("Skipped deletion of %d remote %ss\n", len(deletions), config.DisplayName) + } + } + return nil +} + +func ListSnippets(ctx context.Context, contentType ContentType) ([]uuid.UUID, error) { + if err := flags.LoadConfig(afero.NewOsFs()); err != nil { + return nil, err + } + + config := GetConfig(contentType) + listType := getListParamsType(contentType) + opts := api.V1ProjectListSnippetsParams{Type: &listType} + resp, err := utils.GetSupabase().V1ProjectListSnippetsWithResponse(ctx, flags.ProjectRef, &opts) + if err != nil { + return nil, errors.Errorf("failed to list %ss: %w", config.DisplayName, err) + } + if resp.JSON200 == nil { + return nil, errors.New("unexpected error listing SQL " + config.DisplayName + "s: " + string(resp.Body)) + } + + var snippetIds []uuid.UUID + for _, s := range resp.JSON200.Data { + if s.Visibility != api.SnippetListDataVisibilityProject || !isCorrectType(s.Type, contentType) { + continue + } + uid := uuid.UUID(s.Id) + snippetIds = append(snippetIds, uid) + } + return snippetIds, nil +} + +func DownloadSnippets(ctx context.Context, snippetIds []uuid.UUID, fsys afero.Fs) error { + if err := flags.LoadConfig(fsys); err != nil { + return err + } + + // If no specific snippets provided, download all + if len(snippetIds) == 0 { + allSnippets, err := ListSnippets(ctx, ContentTypeSnippet) + if err != nil { + return err + } + testSnippets, err := ListSnippets(ctx, ContentTypeTest) + if err != nil { + return err + } + snippetIds = append(allSnippets, testSnippets...) + } + + remoteItems := make(map[string]bool) + contentTypesUsed := make(map[ContentType]bool) + + for _, uid := range snippetIds { + bodyResp, err := utils.GetSupabase().V1ProjectGetSnippetWithResponse(ctx, flags.ProjectRef, uid) + if err != nil || bodyResp.JSON200 == nil { + continue + } + + contentType := ContentTypeSnippet + if bodyResp.JSON200.Type == api.SnippetResponseTypeTest { + contentType = ContentTypeTest + } + contentTypesUsed[contentType] = true + config := GetConfig(contentType) + + if err := utils.MkdirIfNotExistFS(fsys, config.Directory); err != nil { + return err + } + + if bodyResp.JSON200.Visibility != api.SnippetResponseVisibilityProject { + continue + } + + fmt.Println("Downloading " + utils.Bold(bodyResp.JSON200.Name)) + safeName := sanitizeFilename(bodyResp.JSON200.Name) + filePath := filepath.Join(config.Directory, safeName+".sql") + remoteItems[safeName+".sql"] = true + + if bodyResp.JSON200.Content.Sql == nil { + fmt.Fprintf(os.Stderr, "missing sql content for %s %s\n", config.DisplayName, bodyResp.JSON200.Name) + continue + } + if err := afero.WriteFile(fsys, filePath, []byte(*bodyResp.JSON200.Content.Sql), 0644); err != nil { + fmt.Fprintf(os.Stderr, "failed to write %s %s: %v\n", config.DisplayName, bodyResp.JSON200.Name, err) + } else { + fmt.Printf("Downloaded %s %s to %s\n", config.DisplayName, utils.Aqua(bodyResp.JSON200.Name), filePath) + } + } + + // Handle local-only file cleanup - only for content types that were actually processed + for ct := range contentTypesUsed { + config := GetConfig(ct) + if exists, err := afero.DirExists(fsys, config.Directory); err == nil && exists { + entries, err := afero.ReadDir(fsys, config.Directory) + if err == nil { + var localOnlyFiles []string + for _, entry := range entries { + if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".sql") { + if !remoteItems[entry.Name()] { + localOnlyFiles = append(localOnlyFiles, entry.Name()) + } + } + } + + if len(localOnlyFiles) > 0 { + console := utils.NewConsole() + itemNames := make([]string, len(localOnlyFiles)) + for i, file := range localOnlyFiles { + itemNames[i] = strings.TrimSuffix(file, ".sql") + } + msg := fmt.Sprintf("Your local %ss directory has %d %s(s) that don't exist remotely:\n %s\nDo you want to delete them locally?", + config.DisplayName, len(localOnlyFiles), config.DisplayName, strings.Join(itemNames, "\n ")) + shouldDelete, err := console.PromptYesNo(ctx, msg, false) + if err != nil { + return err + } + if shouldDelete { + for _, file := range localOnlyFiles { + filePath := filepath.Join(config.Directory, file) + if err := fsys.Remove(filePath); err != nil { + fmt.Fprintf(os.Stderr, "failed to delete %s: %v\n", filePath, err) + } else { + fmt.Printf("Deleted local %s %s\n", config.DisplayName, strings.TrimSuffix(file, ".sql")) + } + } + } else { + fmt.Printf("Skipped deletion of %d local %ss\n", len(localOnlyFiles), config.DisplayName) + } + } + } + } + } + + return nil +} + +func DownloadAll(ctx context.Context, fsys afero.Fs, contentType ContentType) error { + snippetIds, err := ListSnippets(ctx, contentType) + if err != nil { + return err + } + return DownloadSnippets(ctx, snippetIds, fsys) +} + +func DownloadOne(ctx context.Context, fsys afero.Fs, itemId string, contentType ContentType) error { + id, err := uuid.Parse(itemId) + if err != nil { + return fmt.Errorf("invalid %s ID: %w", GetConfig(contentType).DisplayName, err) + } + return DownloadSnippets(ctx, []uuid.UUID{id}, fsys) +} + +func listRemote(ctx context.Context, contentType ContentType) (map[string]uuid.UUID, error) { + listType := getListParamsType(contentType) + opts := api.V1ProjectListSnippetsParams{Type: &listType} + resp, err := utils.GetSupabase().V1ProjectListSnippetsWithResponse(ctx, flags.ProjectRef, &opts) + if err != nil { + return nil, err + } + if resp.JSON200 == nil { + return nil, errors.New(string(resp.Body)) + } + m := map[string]uuid.UUID{} + for _, s := range resp.JSON200.Data { + if !isCorrectType(s.Type, contentType) || s.Visibility != api.SnippetListDataVisibilityProject { + continue + } + id := uuid.UUID(s.Id) + m[s.Name] = id + } + return m, nil +} + +func upsert(ctx context.Context, contentType ContentType, id uuid.UUID, name, sql string) error { + content := map[string]interface{}{ + "favorite": false, + "schema_version": schemaVersion, + "sql": sql, + } + body := api.UpsertContentBody{ + Id: id.String(), + Name: name, + OwnerId: 0, + Type: getUpsertBodyType(contentType), + Visibility: api.UpsertContentBodyVisibilityProject, + Content: &content, + } + resp, err := utils.GetSupabase().V1ProjectUpdateSnippetWithResponse(ctx, flags.ProjectRef, id, body) + if err != nil { + return errors.Errorf("failed to upsert: %w", err) + } + if resp.StatusCode() >= 300 { + return errors.New("failed to upsert: " + string(resp.Body)) + } + return nil +} + +func create(ctx context.Context, contentType ContentType, name, sql string) error { + content := map[string]interface{}{ + "favorite": false, + "schema_version": schemaVersion, + "sql": sql, + } + body := api.CreateContentBody{ + Name: name, + Type: getCreateBodyType(contentType), + Visibility: api.CreateContentBodyVisibilityProject, + Content: &content, + } + resp, err := utils.GetSupabase().V1ProjectCreateSnippetWithResponse(ctx, flags.ProjectRef, body) + if err != nil { + return errors.Errorf("failed to create: %w", err) + } + if resp.StatusCode() >= 300 { + return errors.New("failed to create: " + string(resp.Body)) + } + return nil +} + +func sanitizeFilename(name string) string { + replacer := strings.NewReplacer("/", "_", "\\", "_") + return replacer.Replace(name) +} + +func getListParamsType(contentType ContentType) api.V1ProjectListSnippetsParamsType { + switch contentType { + case ContentTypeTest: + return api.V1ProjectListSnippetsParamsTypeTest + case ContentTypeSnippet: + return api.V1ProjectListSnippetsParamsTypeSql + default: + panic("unsupported content type") + } +} + +func getUpsertBodyType(contentType ContentType) api.UpsertContentBodyType { + return api.UpsertContentBodyType(contentType) +} + +func getCreateBodyType(contentType ContentType) api.CreateContentBodyType { + switch contentType { + case ContentTypeTest: + return api.CreateContentBodyTypeTest + case ContentTypeSnippet: + return api.CreateContentBodyTypeSql + default: + panic("unsupported content type") + } +} + +func isCorrectType(apiType api.SnippetListDataType, contentType ContentType) bool { + switch contentType { + case ContentTypeTest: + return apiType == api.SnippetListDataTypeTest + case ContentTypeSnippet: + return apiType == api.SnippetListDataTypeSql + default: + return false + } +} + +func isCorrectResponseType(apiType api.SnippetResponseType, contentType ContentType) bool { + switch contentType { + case ContentTypeTest: + return apiType == api.SnippetResponseTypeTest + case ContentTypeSnippet: + return apiType == api.SnippetResponseTypeSql + default: + return false + } +} \ No newline at end of file diff --git a/internal/snippets/download/download.go b/internal/snippets/download/download.go index 22b45dd68..a497ddc55 100644 --- a/internal/snippets/download/download.go +++ b/internal/snippets/download/download.go @@ -2,29 +2,15 @@ package download import ( "context" - "fmt" + "strings" - "github.com/go-errors/errors" - "github.com/google/uuid" "github.com/spf13/afero" - "github.com/supabase/cli/internal/utils" + "github.com/supabase/cli/internal/content" ) func Run(ctx context.Context, snippetId string, fsys afero.Fs) error { - // Convert string to UUID - id, err := uuid.Parse(snippetId) - if err != nil { - return fmt.Errorf("invalid snippet ID: %w", err) + if strings.TrimSpace(snippetId) == "" { + return content.DownloadAll(ctx, fsys, content.ContentTypeSnippet) } - resp, err := utils.GetSupabase().V1GetASnippetWithResponse(ctx, id) - if err != nil { - return errors.Errorf("failed to download snippet: %w", err) - } - - if resp.JSON200 == nil { - return errors.New("Unexpected error downloading SQL snippet: " + string(resp.Body)) - } - - fmt.Println(resp.JSON200.Content.Sql) - return nil + return content.DownloadOne(ctx, fsys, snippetId, content.ContentTypeSnippet) } diff --git a/internal/snippets/download/download_test.go b/internal/snippets/download/download_test.go new file mode 100644 index 000000000..07b7e11cb --- /dev/null +++ b/internal/snippets/download/download_test.go @@ -0,0 +1,64 @@ +package download + +import ( + "context" + "net/http" + "path/filepath" + "testing" + + "github.com/h2non/gock" + "github.com/google/uuid" + "github.com/spf13/afero" + "github.com/spf13/viper" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/supabase/cli/internal/testing/apitest" + "github.com/supabase/cli/internal/utils" + "github.com/supabase/cli/internal/utils/flags" +) + +func TestDownloadAll(t *testing.T) { + viper.Set("YES", true) + flags.ProjectRef = apitest.RandomProjectRef() + token := apitest.RandomAccessToken(t) + t.Setenv("SUPABASE_ACCESS_TOKEN", string(token)) + + fsys := afero.NewMemMapFs() + snippetsDir := utils.SnippetsDir + require.NoError(t, fsys.MkdirAll(snippetsDir, 0755)) + // Pre-create an orphan file that should be deleted after confirmation + orphanPath := filepath.Join(snippetsDir, "old.sql") + require.NoError(t, afero.WriteFile(fsys, orphanPath, []byte("old"), 0644)) + + // Prepare remote snippet "new" + newID := uuid.New() + defer gock.OffAll() + gock.New(utils.DefaultApiHost). + Get("/v1/projects/" + flags.ProjectRef + "/snippets"). + MatchParam("type", "sql"). + Reply(http.StatusOK). + JSON(map[string]interface{}{ + "data": []map[string]interface{}{ + {"id": newID.String(), "name": "new", "type": "sql", "visibility": "project"}, + }, + }) + gock.New(utils.DefaultApiHost). + Get("/v1/projects/" + flags.ProjectRef + "/snippets/" + newID.String()). + Reply(http.StatusOK). + JSON(map[string]interface{}{ + "content": map[string]interface{}{"sql": "select 1;"}, + "type": "sql", + "visibility": "project", + }) + + // Run download (empty id downloads all) + err := Run(context.Background(), "", fsys) + assert.NoError(t, err) + + // Verify new file created and orphan removed + exists, _ := afero.Exists(fsys, filepath.Join(snippetsDir, "new.sql")) + assert.True(t, exists) + orphanExists, _ := afero.Exists(fsys, orphanPath) + assert.False(t, orphanExists) + assert.Empty(t, apitest.ListUnmatchedRequests()) +} \ No newline at end of file diff --git a/internal/snippets/push/push.go b/internal/snippets/push/push.go new file mode 100644 index 000000000..b8859c9f1 --- /dev/null +++ b/internal/snippets/push/push.go @@ -0,0 +1,12 @@ +package push + +import ( + "context" + + "github.com/spf13/afero" + "github.com/supabase/cli/internal/content" +) + +func Run(ctx context.Context, fsys afero.Fs) error { + return content.Push(ctx, fsys, content.ContentTypeSnippet) +} \ No newline at end of file diff --git a/internal/snippets/push/push_test.go b/internal/snippets/push/push_test.go new file mode 100644 index 000000000..1f89036d8 --- /dev/null +++ b/internal/snippets/push/push_test.go @@ -0,0 +1,64 @@ +package push + +import ( + "context" + "net/http" + "path/filepath" + "testing" + + "github.com/h2non/gock" + "github.com/google/uuid" + "github.com/spf13/afero" + "github.com/spf13/viper" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/supabase/cli/internal/testing/apitest" + "github.com/supabase/cli/internal/utils" + "github.com/supabase/cli/internal/utils/flags" +) + +// TestPushCommand verifies that running `supabase snippets push` succeeds when +// local snippets differ from remote ones and the user auto-confirms deletions. +func TestPushCommand(t *testing.T) { + // Automatically answer all prompts with "yes" + viper.Set("YES", true) + // Random project ref and valid access token + flags.ProjectRef = apitest.RandomProjectRef() + token := apitest.RandomAccessToken(t) + t.Setenv("SUPABASE_ACCESS_TOKEN", string(token)) + + // Prepare in-memory filesystem with one local snippet "hello.sql" + fsys := afero.NewMemMapFs() + snippetDir := utils.SnippetsDir + require.NoError(t, fsys.MkdirAll(snippetDir, 0755)) + require.NoError(t, afero.WriteFile(fsys, filepath.Join(snippetDir, "hello.sql"), []byte("select 1;"), 0644)) + + // Prepare mock API + helloID := uuid.New() + orphanID := uuid.New() + defer gock.OffAll() + // List existing snippets + gock.New(utils.DefaultApiHost). + Get("/v1/projects/" + flags.ProjectRef + "/snippets"). + MatchParam("type", "sql"). + Reply(http.StatusOK). + JSON(map[string]interface{}{ // minimal JSON required by the client + "data": []map[string]interface{}{ + {"id": helloID.String(), "name": "hello", "type": "sql", "visibility": "project"}, + {"id": orphanID.String(), "name": "orphan", "type": "sql", "visibility": "project"}, + }, + }) + // Upsert local snippet "hello" + gock.New(utils.DefaultApiHost). + Put("/v1/projects/" + flags.ProjectRef + "/snippets/" + helloID.String()). + Reply(http.StatusOK) + // Delete remote orphaned snippet after confirmation + gock.New(utils.DefaultApiHost). + Delete("/v1/projects/" + flags.ProjectRef + "/snippets/" + orphanID.String()). + Reply(http.StatusOK) + + // Execute command + err := Run(context.Background(), fsys) + assert.NoError(t, err) + assert.Empty(t, apitest.ListUnmatchedRequests()) +} \ No newline at end of file diff --git a/internal/tests/download/download.go b/internal/tests/download/download.go new file mode 100644 index 000000000..503f84317 --- /dev/null +++ b/internal/tests/download/download.go @@ -0,0 +1,16 @@ +package download + +import ( + "context" + "strings" + + "github.com/spf13/afero" + "github.com/supabase/cli/internal/content" +) + +func Run(ctx context.Context, testId string, fsys afero.Fs) error { + if strings.TrimSpace(testId) == "" { + return content.DownloadAll(ctx, fsys, content.ContentTypeTest) + } + return content.DownloadOne(ctx, fsys, testId, content.ContentTypeTest) +} \ No newline at end of file diff --git a/internal/tests/download/download_test.go b/internal/tests/download/download_test.go new file mode 100644 index 000000000..70593830c --- /dev/null +++ b/internal/tests/download/download_test.go @@ -0,0 +1,60 @@ +package download + +import ( + "context" + "net/http" + "path/filepath" + "testing" + + "github.com/h2non/gock" + "github.com/google/uuid" + "github.com/spf13/afero" + "github.com/spf13/viper" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/supabase/cli/internal/testing/apitest" + "github.com/supabase/cli/internal/utils" + "github.com/supabase/cli/internal/utils/flags" +) + +func TestDownloadAll(t *testing.T) { + viper.Set("YES", true) + flags.ProjectRef = apitest.RandomProjectRef() + token := apitest.RandomAccessToken(t) + t.Setenv("SUPABASE_ACCESS_TOKEN", string(token)) + + fsys := afero.NewMemMapFs() + testsDir := utils.TestsDir + require.NoError(t, fsys.MkdirAll(testsDir, 0755)) + orphanPath := filepath.Join(testsDir, "legacy.sql") + require.NoError(t, afero.WriteFile(fsys, orphanPath, []byte("legacy"), 0644)) + + newID := uuid.New() + defer gock.OffAll() + gock.New(utils.DefaultApiHost). + Get("/v1/projects/" + flags.ProjectRef + "/snippets"). + MatchParam("type", "test"). + Reply(http.StatusOK). + JSON(map[string]interface{}{ + "data": []map[string]interface{}{ + {"id": newID.String(), "name": "delta", "type": "test", "visibility": "project"}, + }, + }) + gock.New(utils.DefaultApiHost). + Get("/v1/projects/" + flags.ProjectRef + "/snippets/" + newID.String()). + Reply(http.StatusOK). + JSON(map[string]interface{}{ + "content": map[string]interface{}{"sql": "select 2;"}, + "type": "test", + "visibility": "project", + }) + + err := Run(context.Background(), "", fsys) + assert.NoError(t, err) + + exists, _ := afero.Exists(fsys, filepath.Join(testsDir, "delta.sql")) + assert.True(t, exists) + orphanExists, _ := afero.Exists(fsys, orphanPath) + assert.False(t, orphanExists) + assert.Empty(t, apitest.ListUnmatchedRequests()) +} \ No newline at end of file diff --git a/internal/tests/push/push.go b/internal/tests/push/push.go new file mode 100644 index 000000000..4d7c7e99d --- /dev/null +++ b/internal/tests/push/push.go @@ -0,0 +1,12 @@ +package push + +import ( + "context" + + "github.com/spf13/afero" + "github.com/supabase/cli/internal/content" +) + +func Run(ctx context.Context, fsys afero.Fs) error { + return content.Push(ctx, fsys, content.ContentTypeTest) +} \ No newline at end of file diff --git a/internal/tests/push/push_test.go b/internal/tests/push/push_test.go new file mode 100644 index 000000000..c04465f83 --- /dev/null +++ b/internal/tests/push/push_test.go @@ -0,0 +1,54 @@ +package push + +import ( + "context" + "net/http" + "path/filepath" + "testing" + + "github.com/h2non/gock" + "github.com/google/uuid" + "github.com/spf13/afero" + "github.com/spf13/viper" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/supabase/cli/internal/testing/apitest" + "github.com/supabase/cli/internal/utils" + "github.com/supabase/cli/internal/utils/flags" +) + +func TestPushCommand(t *testing.T) { + viper.Set("YES", true) + flags.ProjectRef = apitest.RandomProjectRef() + token := apitest.RandomAccessToken(t) + t.Setenv("SUPABASE_ACCESS_TOKEN", string(token)) + + fsys := afero.NewMemMapFs() + testsDir := utils.TestsDir + require.NoError(t, fsys.MkdirAll(testsDir, 0755)) + require.NoError(t, afero.WriteFile(fsys, filepath.Join(testsDir, "alpha.sql"), []byte("select 1;"), 0644)) + + alphaID := uuid.New() + betaID := uuid.New() + defer gock.OffAll() + gock.New(utils.DefaultApiHost). + Get("/v1/projects/" + flags.ProjectRef + "/snippets"). + MatchParam("type", "test"). + Reply(http.StatusOK). + JSON(map[string]interface{}{ + "data": []map[string]interface{}{ + {"id": alphaID.String(), "name": "alpha", "type": "test", "visibility": "project"}, + {"id": betaID.String(), "name": "beta", "type": "test", "visibility": "project"}, + }, + }) + gock.New(utils.DefaultApiHost). + Put("/v1/projects/" + flags.ProjectRef + "/snippets/" + alphaID.String()). + Reply(http.StatusOK) + gock.New(utils.DefaultApiHost). + Delete("/v1/projects/" + flags.ProjectRef + "/snippets/" + betaID.String()). + Reply(http.StatusOK) + + err := Run(context.Background(), fsys) + assert.NoError(t, err) + assert.Empty(t, apitest.ListUnmatchedRequests()) +} \ No newline at end of file diff --git a/internal/utils/cloudflare/dns_test.go b/internal/utils/cloudflare/dns_test.go index ee4d00c29..3d6c28b87 100644 --- a/internal/utils/cloudflare/dns_test.go +++ b/internal/utils/cloudflare/dns_test.go @@ -22,7 +22,7 @@ func TestDNSQuery(t *testing.T) { JSON(DNSResponse{ Answer: []DNSAnswer{ { - Name: "example.com", + "name": "example.com", Type: TypeA, Ttl: 300, Data: "93.184.216.34", @@ -31,7 +31,7 @@ func TestDNSQuery(t *testing.T) { }) resp, err := api.DNSQuery(context.Background(), DNSParams{ - Name: "example.com", + "name": "example.com", }) assert.NoError(t, err) @@ -54,7 +54,7 @@ func TestDNSQuery(t *testing.T) { JSON(DNSResponse{ Answer: []DNSAnswer{ { - Name: "www.example.com", + "name": "www.example.com", Type: TypeCNAME, Ttl: 3600, Data: "example.com", @@ -63,7 +63,7 @@ func TestDNSQuery(t *testing.T) { }) resp, err := api.DNSQuery(context.Background(), DNSParams{ - Name: "www.example.com", + "name": "www.example.com", Type: &dnsType, }) @@ -83,7 +83,7 @@ func TestDNSQuery(t *testing.T) { ReplyError(gock.ErrCannotMatch) resp, err := api.DNSQuery(context.Background(), DNSParams{ - Name: "example.com", + "name": "example.com", }) assert.Error(t, err) @@ -100,7 +100,7 @@ func TestDNSQuery(t *testing.T) { Reply(http.StatusServiceUnavailable) resp, err := api.DNSQuery(context.Background(), DNSParams{ - Name: "example.com", + "name": "example.com", }) assert.ErrorContains(t, err, "status 503") @@ -118,7 +118,7 @@ func TestDNSQuery(t *testing.T) { JSON("invalid json") resp, err := api.DNSQuery(context.Background(), DNSParams{ - Name: "example.com", + "name": "example.com", }) assert.ErrorContains(t, err, "failed to parse") diff --git a/internal/utils/misc.go b/internal/utils/misc.go index 80fb13b27..b9709152d 100644 --- a/internal/utils/misc.go +++ b/internal/utils/misc.go @@ -78,9 +78,11 @@ var ( SchemasDir = filepath.Join(SupabaseDirPath, "schemas") MigrationsDir = filepath.Join(SupabaseDirPath, "migrations") FunctionsDir = filepath.Join(SupabaseDirPath, "functions") + SnippetsDir = filepath.Join(SupabaseDirPath, "snippets") FallbackImportMapPath = filepath.Join(FunctionsDir, "import_map.json") FallbackEnvFilePath = filepath.Join(FunctionsDir, ".env") DbTestsDir = filepath.Join(SupabaseDirPath, "tests") + TestsDir = filepath.Join(SupabaseDirPath, "tests", "database") CustomRolesPath = filepath.Join(SupabaseDirPath, "roles.sql") ErrNotLinked = errors.Errorf("Cannot find project ref. Have you run %s?", Aqua("supabase link")) diff --git a/pkg/api/client.gen.go b/pkg/api/client.gen.go index 45e92c6a4..476beef4a 100644 --- a/pkg/api/client.gen.go +++ b/pkg/api/client.gen.go @@ -507,6 +507,25 @@ type ClientInterface interface { V1BulkCreateSecrets(ctx context.Context, ref string, body V1BulkCreateSecretsJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + // V1ProjectListSnippets request + V1ProjectListSnippets(ctx context.Context, ref string, params *V1ProjectListSnippetsParams, reqEditors ...RequestEditorFn) (*http.Response, error) + + // V1ProjectCreateSnippetWithBody request with any body + V1ProjectCreateSnippetWithBody(ctx context.Context, ref string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + V1ProjectCreateSnippet(ctx context.Context, ref string, body V1ProjectCreateSnippetJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // V1ProjectDeleteSnippet request + V1ProjectDeleteSnippet(ctx context.Context, ref string, id openapi_types.UUID, reqEditors ...RequestEditorFn) (*http.Response, error) + + // V1ProjectGetSnippet request + V1ProjectGetSnippet(ctx context.Context, ref string, id openapi_types.UUID, reqEditors ...RequestEditorFn) (*http.Response, error) + + // V1ProjectUpdateSnippetWithBody request with any body + V1ProjectUpdateSnippetWithBody(ctx context.Context, ref string, id openapi_types.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + V1ProjectUpdateSnippet(ctx context.Context, ref string, id openapi_types.UUID, body V1ProjectUpdateSnippetJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + // V1GetSslEnforcementConfig request V1GetSslEnforcementConfig(ctx context.Context, ref string, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -2379,6 +2398,90 @@ func (c *Client) V1BulkCreateSecrets(ctx context.Context, ref string, body V1Bul return c.Client.Do(req) } +func (c *Client) V1ProjectListSnippets(ctx context.Context, ref string, params *V1ProjectListSnippetsParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewV1ProjectListSnippetsRequest(c.Server, ref, params) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) V1ProjectCreateSnippetWithBody(ctx context.Context, ref string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewV1ProjectCreateSnippetRequestWithBody(c.Server, ref, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) V1ProjectCreateSnippet(ctx context.Context, ref string, body V1ProjectCreateSnippetJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewV1ProjectCreateSnippetRequest(c.Server, ref, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) V1ProjectDeleteSnippet(ctx context.Context, ref string, id openapi_types.UUID, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewV1ProjectDeleteSnippetRequest(c.Server, ref, id) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) V1ProjectGetSnippet(ctx context.Context, ref string, id openapi_types.UUID, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewV1ProjectGetSnippetRequest(c.Server, ref, id) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) V1ProjectUpdateSnippetWithBody(ctx context.Context, ref string, id openapi_types.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewV1ProjectUpdateSnippetRequestWithBody(c.Server, ref, id, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) V1ProjectUpdateSnippet(ctx context.Context, ref string, id openapi_types.UUID, body V1ProjectUpdateSnippetJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewV1ProjectUpdateSnippetRequest(c.Server, ref, id, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + func (c *Client) V1GetSslEnforcementConfig(ctx context.Context, ref string, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewV1GetSslEnforcementConfigRequest(c.Server, ref) if err != nil { @@ -7884,11 +7987,323 @@ func NewV1BulkCreateSecretsRequest(server string, ref string, body V1BulkCreateS return nil, err } bodyReader = bytes.NewReader(buf) - return NewV1BulkCreateSecretsRequestWithBody(server, ref, "application/json", bodyReader) + return NewV1BulkCreateSecretsRequestWithBody(server, ref, "application/json", bodyReader) +} + +// NewV1BulkCreateSecretsRequestWithBody generates requests for V1BulkCreateSecrets with any type of body +func NewV1BulkCreateSecretsRequestWithBody(server string, ref string, contentType string, body io.Reader) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "ref", runtime.ParamLocationPath, ref) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/v1/projects/%s/secrets", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewV1ProjectListSnippetsRequest generates requests for V1ProjectListSnippets +func NewV1ProjectListSnippetsRequest(server string, ref string, params *V1ProjectListSnippetsParams) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "ref", runtime.ParamLocationPath, ref) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/v1/projects/%s/snippets", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + if params != nil { + queryValues := queryURL.Query() + + if params.ProjectRef != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "project_ref", runtime.ParamLocationQuery, *params.ProjectRef); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.Type != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "type", runtime.ParamLocationQuery, *params.Type); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.Cursor != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "cursor", runtime.ParamLocationQuery, *params.Cursor); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.Limit != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.SortBy != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "sort_by", runtime.ParamLocationQuery, *params.SortBy); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.SortOrder != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "sort_order", runtime.ParamLocationQuery, *params.SortOrder); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + queryURL.RawQuery = queryValues.Encode() + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewV1ProjectCreateSnippetRequest calls the generic V1ProjectCreateSnippet builder with application/json body +func NewV1ProjectCreateSnippetRequest(server string, ref string, body V1ProjectCreateSnippetJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewV1ProjectCreateSnippetRequestWithBody(server, ref, "application/json", bodyReader) +} + +// NewV1ProjectCreateSnippetRequestWithBody generates requests for V1ProjectCreateSnippet with any type of body +func NewV1ProjectCreateSnippetRequestWithBody(server string, ref string, contentType string, body io.Reader) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "ref", runtime.ParamLocationPath, ref) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/v1/projects/%s/snippets", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewV1ProjectDeleteSnippetRequest generates requests for V1ProjectDeleteSnippet +func NewV1ProjectDeleteSnippetRequest(server string, ref string, id openapi_types.UUID) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "ref", runtime.ParamLocationPath, ref) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/v1/projects/%s/snippets/%s", pathParam0, pathParam1) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("DELETE", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewV1ProjectGetSnippetRequest generates requests for V1ProjectGetSnippet +func NewV1ProjectGetSnippetRequest(server string, ref string, id openapi_types.UUID) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "ref", runtime.ParamLocationPath, ref) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/v1/projects/%s/snippets/%s", pathParam0, pathParam1) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewV1ProjectUpdateSnippetRequest calls the generic V1ProjectUpdateSnippet builder with application/json body +func NewV1ProjectUpdateSnippetRequest(server string, ref string, id openapi_types.UUID, body V1ProjectUpdateSnippetJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewV1ProjectUpdateSnippetRequestWithBody(server, ref, id, "application/json", bodyReader) } -// NewV1BulkCreateSecretsRequestWithBody generates requests for V1BulkCreateSecrets with any type of body -func NewV1BulkCreateSecretsRequestWithBody(server string, ref string, contentType string, body io.Reader) (*http.Request, error) { +// NewV1ProjectUpdateSnippetRequestWithBody generates requests for V1ProjectUpdateSnippet with any type of body +func NewV1ProjectUpdateSnippetRequestWithBody(server string, ref string, id openapi_types.UUID, contentType string, body io.Reader) (*http.Request, error) { var err error var pathParam0 string @@ -7898,12 +8313,19 @@ func NewV1BulkCreateSecretsRequestWithBody(server string, ref string, contentTyp return nil, err } + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id) + if err != nil { + return nil, err + } + serverURL, err := url.Parse(server) if err != nil { return nil, err } - operationPath := fmt.Sprintf("/v1/projects/%s/secrets", pathParam0) + operationPath := fmt.Sprintf("/v1/projects/%s/snippets/%s", pathParam0, pathParam1) if operationPath[0] == '/' { operationPath = "." + operationPath } @@ -7913,7 +8335,7 @@ func NewV1BulkCreateSecretsRequestWithBody(server string, ref string, contentTyp return nil, err } - req, err := http.NewRequest("POST", queryURL.String(), body) + req, err := http.NewRequest("PUT", queryURL.String(), body) if err != nil { return nil, err } @@ -8431,6 +8853,22 @@ func NewV1ListAllSnippetsRequest(server string, params *V1ListAllSnippetsParams) } + if params.Type != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "type", runtime.ParamLocationQuery, *params.Type); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + if params.Cursor != nil { if queryFrag, err := runtime.StyleParamWithLocation("form", true, "cursor", runtime.ParamLocationQuery, *params.Cursor); err != nil { @@ -9000,6 +9438,25 @@ type ClientWithResponsesInterface interface { V1BulkCreateSecretsWithResponse(ctx context.Context, ref string, body V1BulkCreateSecretsJSONRequestBody, reqEditors ...RequestEditorFn) (*V1BulkCreateSecretsResponse, error) + // V1ProjectListSnippetsWithResponse request + V1ProjectListSnippetsWithResponse(ctx context.Context, ref string, params *V1ProjectListSnippetsParams, reqEditors ...RequestEditorFn) (*V1ProjectListSnippetsResponse, error) + + // V1ProjectCreateSnippetWithBodyWithResponse request with any body + V1ProjectCreateSnippetWithBodyWithResponse(ctx context.Context, ref string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*V1ProjectCreateSnippetResponse, error) + + V1ProjectCreateSnippetWithResponse(ctx context.Context, ref string, body V1ProjectCreateSnippetJSONRequestBody, reqEditors ...RequestEditorFn) (*V1ProjectCreateSnippetResponse, error) + + // V1ProjectDeleteSnippetWithResponse request + V1ProjectDeleteSnippetWithResponse(ctx context.Context, ref string, id openapi_types.UUID, reqEditors ...RequestEditorFn) (*V1ProjectDeleteSnippetResponse, error) + + // V1ProjectGetSnippetWithResponse request + V1ProjectGetSnippetWithResponse(ctx context.Context, ref string, id openapi_types.UUID, reqEditors ...RequestEditorFn) (*V1ProjectGetSnippetResponse, error) + + // V1ProjectUpdateSnippetWithBodyWithResponse request with any body + V1ProjectUpdateSnippetWithBodyWithResponse(ctx context.Context, ref string, id openapi_types.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*V1ProjectUpdateSnippetResponse, error) + + V1ProjectUpdateSnippetWithResponse(ctx context.Context, ref string, id openapi_types.UUID, body V1ProjectUpdateSnippetJSONRequestBody, reqEditors ...RequestEditorFn) (*V1ProjectUpdateSnippetResponse, error) + // V1GetSslEnforcementConfigWithResponse request V1GetSslEnforcementConfigWithResponse(ctx context.Context, ref string, reqEditors ...RequestEditorFn) (*V1GetSslEnforcementConfigResponse, error) @@ -11507,6 +11964,114 @@ func (r V1BulkCreateSecretsResponse) StatusCode() int { return 0 } +type V1ProjectListSnippetsResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *SnippetList +} + +// Status returns HTTPResponse.Status +func (r V1ProjectListSnippetsResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r V1ProjectListSnippetsResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type V1ProjectCreateSnippetResponse struct { + Body []byte + HTTPResponse *http.Response + JSON201 *SnippetResponse +} + +// Status returns HTTPResponse.Status +func (r V1ProjectCreateSnippetResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r V1ProjectCreateSnippetResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type V1ProjectDeleteSnippetResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r V1ProjectDeleteSnippetResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r V1ProjectDeleteSnippetResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type V1ProjectGetSnippetResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *SnippetResponse +} + +// Status returns HTTPResponse.Status +func (r V1ProjectGetSnippetResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r V1ProjectGetSnippetResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type V1ProjectUpdateSnippetResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r V1ProjectUpdateSnippetResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r V1ProjectUpdateSnippetResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + type V1GetSslEnforcementConfigResponse struct { Body []byte HTTPResponse *http.Response @@ -13121,6 +13686,67 @@ func (c *ClientWithResponses) V1BulkCreateSecretsWithResponse(ctx context.Contex return ParseV1BulkCreateSecretsResponse(rsp) } +// V1ProjectListSnippetsWithResponse request returning *V1ProjectListSnippetsResponse +func (c *ClientWithResponses) V1ProjectListSnippetsWithResponse(ctx context.Context, ref string, params *V1ProjectListSnippetsParams, reqEditors ...RequestEditorFn) (*V1ProjectListSnippetsResponse, error) { + rsp, err := c.V1ProjectListSnippets(ctx, ref, params, reqEditors...) + if err != nil { + return nil, err + } + return ParseV1ProjectListSnippetsResponse(rsp) +} + +// V1ProjectCreateSnippetWithBodyWithResponse request with arbitrary body returning *V1ProjectCreateSnippetResponse +func (c *ClientWithResponses) V1ProjectCreateSnippetWithBodyWithResponse(ctx context.Context, ref string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*V1ProjectCreateSnippetResponse, error) { + rsp, err := c.V1ProjectCreateSnippetWithBody(ctx, ref, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseV1ProjectCreateSnippetResponse(rsp) +} + +func (c *ClientWithResponses) V1ProjectCreateSnippetWithResponse(ctx context.Context, ref string, body V1ProjectCreateSnippetJSONRequestBody, reqEditors ...RequestEditorFn) (*V1ProjectCreateSnippetResponse, error) { + rsp, err := c.V1ProjectCreateSnippet(ctx, ref, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseV1ProjectCreateSnippetResponse(rsp) +} + +// V1ProjectDeleteSnippetWithResponse request returning *V1ProjectDeleteSnippetResponse +func (c *ClientWithResponses) V1ProjectDeleteSnippetWithResponse(ctx context.Context, ref string, id openapi_types.UUID, reqEditors ...RequestEditorFn) (*V1ProjectDeleteSnippetResponse, error) { + rsp, err := c.V1ProjectDeleteSnippet(ctx, ref, id, reqEditors...) + if err != nil { + return nil, err + } + return ParseV1ProjectDeleteSnippetResponse(rsp) +} + +// V1ProjectGetSnippetWithResponse request returning *V1ProjectGetSnippetResponse +func (c *ClientWithResponses) V1ProjectGetSnippetWithResponse(ctx context.Context, ref string, id openapi_types.UUID, reqEditors ...RequestEditorFn) (*V1ProjectGetSnippetResponse, error) { + rsp, err := c.V1ProjectGetSnippet(ctx, ref, id, reqEditors...) + if err != nil { + return nil, err + } + return ParseV1ProjectGetSnippetResponse(rsp) +} + +// V1ProjectUpdateSnippetWithBodyWithResponse request with arbitrary body returning *V1ProjectUpdateSnippetResponse +func (c *ClientWithResponses) V1ProjectUpdateSnippetWithBodyWithResponse(ctx context.Context, ref string, id openapi_types.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*V1ProjectUpdateSnippetResponse, error) { + rsp, err := c.V1ProjectUpdateSnippetWithBody(ctx, ref, id, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseV1ProjectUpdateSnippetResponse(rsp) +} + +func (c *ClientWithResponses) V1ProjectUpdateSnippetWithResponse(ctx context.Context, ref string, id openapi_types.UUID, body V1ProjectUpdateSnippetJSONRequestBody, reqEditors ...RequestEditorFn) (*V1ProjectUpdateSnippetResponse, error) { + rsp, err := c.V1ProjectUpdateSnippet(ctx, ref, id, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseV1ProjectUpdateSnippetResponse(rsp) +} + // V1GetSslEnforcementConfigWithResponse request returning *V1GetSslEnforcementConfigResponse func (c *ClientWithResponses) V1GetSslEnforcementConfigWithResponse(ctx context.Context, ref string, reqEditors ...RequestEditorFn) (*V1GetSslEnforcementConfigResponse, error) { rsp, err := c.V1GetSslEnforcementConfig(ctx, ref, reqEditors...) @@ -15938,6 +16564,116 @@ func ParseV1BulkCreateSecretsResponse(rsp *http.Response) (*V1BulkCreateSecretsR return response, nil } +// ParseV1ProjectListSnippetsResponse parses an HTTP response from a V1ProjectListSnippetsWithResponse call +func ParseV1ProjectListSnippetsResponse(rsp *http.Response) (*V1ProjectListSnippetsResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &V1ProjectListSnippetsResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest SnippetList + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseV1ProjectCreateSnippetResponse parses an HTTP response from a V1ProjectCreateSnippetWithResponse call +func ParseV1ProjectCreateSnippetResponse(rsp *http.Response) (*V1ProjectCreateSnippetResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &V1ProjectCreateSnippetResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 201: + var dest SnippetResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON201 = &dest + + } + + return response, nil +} + +// ParseV1ProjectDeleteSnippetResponse parses an HTTP response from a V1ProjectDeleteSnippetWithResponse call +func ParseV1ProjectDeleteSnippetResponse(rsp *http.Response) (*V1ProjectDeleteSnippetResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &V1ProjectDeleteSnippetResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseV1ProjectGetSnippetResponse parses an HTTP response from a V1ProjectGetSnippetWithResponse call +func ParseV1ProjectGetSnippetResponse(rsp *http.Response) (*V1ProjectGetSnippetResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &V1ProjectGetSnippetResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest SnippetResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseV1ProjectUpdateSnippetResponse parses an HTTP response from a V1ProjectUpdateSnippetWithResponse call +func ParseV1ProjectUpdateSnippetResponse(rsp *http.Response) (*V1ProjectUpdateSnippetResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &V1ProjectUpdateSnippetResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + // ParseV1GetSslEnforcementConfigResponse parses an HTTP response from a V1GetSslEnforcementConfigWithResponse call func ParseV1GetSslEnforcementConfigResponse(rsp *http.Response) (*V1GetSslEnforcementConfigResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) diff --git a/pkg/api/types.gen.go b/pkg/api/types.gen.go index 061d3b3f6..626f91ada 100644 --- a/pkg/api/types.gen.go +++ b/pkg/api/types.gen.go @@ -198,6 +198,22 @@ const ( CreateBranchBodyReleaseChannelWithdrawn CreateBranchBodyReleaseChannel = "withdrawn" ) +// Defines values for CreateContentBodyType. +const ( + CreateContentBodyTypeLogSql CreateContentBodyType = "log_sql" + CreateContentBodyTypeReport CreateContentBodyType = "report" + CreateContentBodyTypeSql CreateContentBodyType = "sql" + CreateContentBodyTypeTest CreateContentBodyType = "test" +) + +// Defines values for CreateContentBodyVisibility. +const ( + CreateContentBodyVisibilityOrg CreateContentBodyVisibility = "org" + CreateContentBodyVisibilityProject CreateContentBodyVisibility = "project" + CreateContentBodyVisibilityPublic CreateContentBodyVisibility = "public" + CreateContentBodyVisibilityUser CreateContentBodyVisibility = "user" +) + // Defines values for CreateProviderBodyType. const ( Saml CreateProviderBodyType = "saml" @@ -494,7 +510,7 @@ const ( // Defines values for OAuthTokenBodyResource. const ( - OAuthTokenBodyResourceHttpsapiSupabaseGreenmcp OAuthTokenBodyResource = "https://api.supabase.green/mcp" + OAuthTokenBodyResourceHttplocalhost8080mcp OAuthTokenBodyResource = "http://localhost:8080/mcp" ) // Defines values for OAuthTokenResponseTokenType. @@ -608,7 +624,8 @@ const ( // Defines values for SnippetListDataType. const ( - SnippetListDataTypeSql SnippetListDataType = "sql" + SnippetListDataTypeSql SnippetListDataType = "sql" + SnippetListDataTypeTest SnippetListDataType = "test" ) // Defines values for SnippetListDataVisibility. @@ -621,7 +638,8 @@ const ( // Defines values for SnippetResponseType. const ( - SnippetResponseTypeSql SnippetResponseType = "sql" + SnippetResponseTypeSql SnippetResponseType = "sql" + SnippetResponseTypeTest SnippetResponseType = "test" ) // Defines values for SnippetResponseVisibility. @@ -717,6 +735,22 @@ const ( UpgradeDatabaseBodyReleaseChannelWithdrawn UpgradeDatabaseBodyReleaseChannel = "withdrawn" ) +// Defines values for UpsertContentBodyType. +const ( + UpsertContentBodyTypeLogSql UpsertContentBodyType = "log_sql" + UpsertContentBodyTypeReport UpsertContentBodyType = "report" + UpsertContentBodyTypeSql UpsertContentBodyType = "sql" + UpsertContentBodyTypeTest UpsertContentBodyType = "test" +) + +// Defines values for UpsertContentBodyVisibility. +const ( + UpsertContentBodyVisibilityOrg UpsertContentBodyVisibility = "org" + UpsertContentBodyVisibilityProject UpsertContentBodyVisibility = "project" + UpsertContentBodyVisibilityPublic UpsertContentBodyVisibility = "public" + UpsertContentBodyVisibilityUser UpsertContentBodyVisibility = "user" +) + // Defines values for V1BackupsResponseBackupsStatus. const ( V1BackupsResponseBackupsStatusARCHIVED V1BackupsResponseBackupsStatus = "ARCHIVED" @@ -961,7 +995,7 @@ const ( // Defines values for V1AuthorizeUserParamsResource. const ( - V1AuthorizeUserParamsResourceHttpsapiSupabaseGreenmcp V1AuthorizeUserParamsResource = "https://api.supabase.green/mcp" + V1AuthorizeUserParamsResourceHttplocalhost8080mcp V1AuthorizeUserParamsResource = "http://localhost:8080/mcp" ) // Defines values for V1OauthAuthorizeProjectClaimParamsResponseType. @@ -980,7 +1014,7 @@ const ( // Defines values for V1GetSecurityAdvisorsParamsLintType. const ( - Sql V1GetSecurityAdvisorsParamsLintType = "sql" + V1GetSecurityAdvisorsParamsLintTypeSql V1GetSecurityAdvisorsParamsLintType = "sql" ) // Defines values for V1GetProjectUsageApiCountParamsInterval. @@ -1004,16 +1038,40 @@ const ( Storage V1GetServicesHealthParamsServices = "storage" ) +// Defines values for V1ProjectListSnippetsParamsType. +const ( + V1ProjectListSnippetsParamsTypeSql V1ProjectListSnippetsParamsType = "sql" + V1ProjectListSnippetsParamsTypeTest V1ProjectListSnippetsParamsType = "test" +) + +// Defines values for V1ProjectListSnippetsParamsSortBy. +const ( + V1ProjectListSnippetsParamsSortByInsertedAt V1ProjectListSnippetsParamsSortBy = "inserted_at" + V1ProjectListSnippetsParamsSortByName V1ProjectListSnippetsParamsSortBy = "name" +) + +// Defines values for V1ProjectListSnippetsParamsSortOrder. +const ( + V1ProjectListSnippetsParamsSortOrderAsc V1ProjectListSnippetsParamsSortOrder = "asc" + V1ProjectListSnippetsParamsSortOrderDesc V1ProjectListSnippetsParamsSortOrder = "desc" +) + +// Defines values for V1ListAllSnippetsParamsType. +const ( + Sql V1ListAllSnippetsParamsType = "sql" + Test V1ListAllSnippetsParamsType = "test" +) + // Defines values for V1ListAllSnippetsParamsSortBy. const ( - InsertedAt V1ListAllSnippetsParamsSortBy = "inserted_at" - Name V1ListAllSnippetsParamsSortBy = "name" + V1ListAllSnippetsParamsSortByInsertedAt V1ListAllSnippetsParamsSortBy = "inserted_at" + V1ListAllSnippetsParamsSortByName V1ListAllSnippetsParamsSortBy = "name" ) // Defines values for V1ListAllSnippetsParamsSortOrder. const ( - Asc V1ListAllSnippetsParamsSortOrder = "asc" - Desc V1ListAllSnippetsParamsSortOrder = "desc" + V1ListAllSnippetsParamsSortOrderAsc V1ListAllSnippetsParamsSortOrder = "asc" + V1ListAllSnippetsParamsSortOrderDesc V1ListAllSnippetsParamsSortOrder = "desc" ) // ActivateVanitySubdomainResponse defines model for ActivateVanitySubdomainResponse. @@ -1051,18 +1109,16 @@ type AnalyticsResponse_Error struct { // ApiKeyResponse defines model for ApiKeyResponse. type ApiKeyResponse struct { - ApiKey nullable.Nullable[string] `json:"api_key,omitempty"` - Description nullable.Nullable[string] `json:"description,omitempty"` - Hash nullable.Nullable[string] `json:"hash,omitempty"` - Id nullable.Nullable[string] `json:"id,omitempty"` - InsertedAt nullable.Nullable[time.Time] `json:"inserted_at,omitempty"` - Name string `json:"name"` - Prefix nullable.Nullable[string] `json:"prefix,omitempty"` - SecretJwtTemplate nullable.Nullable[struct { - Role string `json:"role"` - }] `json:"secret_jwt_template,omitempty"` - Type nullable.Nullable[ApiKeyResponseType] `json:"type,omitempty"` - UpdatedAt nullable.Nullable[time.Time] `json:"updated_at,omitempty"` + ApiKey nullable.Nullable[string] `json:"api_key,omitempty"` + Description nullable.Nullable[string] `json:"description,omitempty"` + Hash nullable.Nullable[string] `json:"hash,omitempty"` + Id nullable.Nullable[string] `json:"id,omitempty"` + InsertedAt nullable.Nullable[time.Time] `json:"inserted_at,omitempty"` + Name string `json:"name"` + Prefix nullable.Nullable[string] `json:"prefix,omitempty"` + SecretJwtTemplate nullable.Nullable[map[string]interface{}] `json:"secret_jwt_template,omitempty"` + Type nullable.Nullable[ApiKeyResponseType] `json:"type,omitempty"` + UpdatedAt nullable.Nullable[time.Time] `json:"updated_at,omitempty"` } // ApiKeyResponseType defines model for ApiKeyResponse.Type. @@ -1385,12 +1441,10 @@ type BulkUpdateFunctionResponseFunctionsStatus string // CreateApiKeyBody defines model for CreateApiKeyBody. type CreateApiKeyBody struct { - Description nullable.Nullable[string] `json:"description,omitempty"` - Name string `json:"name"` - SecretJwtTemplate nullable.Nullable[struct { - Role string `json:"role"` - }] `json:"secret_jwt_template,omitempty"` - Type CreateApiKeyBodyType `json:"type"` + Description nullable.Nullable[string] `json:"description,omitempty"` + Name string `json:"name"` + SecretJwtTemplate nullable.Nullable[map[string]interface{}] `json:"secret_jwt_template,omitempty"` + Type CreateApiKeyBodyType `json:"type"` } // CreateApiKeyBodyType defines model for CreateApiKeyBody.Type. @@ -1423,6 +1477,24 @@ type CreateBranchBodyPostgresEngine string // CreateBranchBodyReleaseChannel Release channel. If not provided, GA will be used. type CreateBranchBodyReleaseChannel string +// CreateContentBody defines model for CreateContentBody. +type CreateContentBody struct { + Content *map[string]interface{} `json:"content,omitempty"` + Description *string `json:"description,omitempty"` + FolderId nullable.Nullable[openapi_types.UUID] `json:"folder_id,omitempty"` + Id *string `json:"id,omitempty"` + Name string `json:"name"` + OwnerId *float32 `json:"owner_id,omitempty"` + Type CreateContentBodyType `json:"type"` + Visibility CreateContentBodyVisibility `json:"visibility"` +} + +// CreateContentBodyType defines model for CreateContentBody.Type. +type CreateContentBodyType string + +// CreateContentBodyVisibility defines model for CreateContentBody.Visibility. +type CreateContentBodyVisibility string + // CreateOrganizationV1 defines model for CreateOrganizationV1. type CreateOrganizationV1 struct { Name string `json:"name"` @@ -2175,7 +2247,7 @@ type SnippetList struct { Cursor *string `json:"cursor,omitempty"` Data []struct { Description nullable.Nullable[string] `json:"description"` - Id string `json:"id"` + Id openapi_types.UUID `json:"id"` InsertedAt string `json:"inserted_at"` Name string `json:"name"` Owner struct { @@ -2205,12 +2277,12 @@ type SnippetListDataVisibility string // SnippetResponse defines model for SnippetResponse. type SnippetResponse struct { Content struct { - Favorite bool `json:"favorite"` - SchemaVersion string `json:"schema_version"` - Sql string `json:"sql"` + Favorite *bool `json:"favorite,omitempty"` + SchemaVersion *string `json:"schema_version,omitempty"` + Sql *string `json:"sql,omitempty"` } `json:"content"` Description nullable.Nullable[string] `json:"description"` - Id string `json:"id"` + Id openapi_types.UUID `json:"id"` InsertedAt string `json:"inserted_at"` Name string `json:"name"` Owner struct { @@ -2316,11 +2388,9 @@ type TypescriptResponse struct { // UpdateApiKeyBody defines model for UpdateApiKeyBody. type UpdateApiKeyBody struct { - Description nullable.Nullable[string] `json:"description,omitempty"` - Name *string `json:"name,omitempty"` - SecretJwtTemplate nullable.Nullable[struct { - Role string `json:"role"` - }] `json:"secret_jwt_template,omitempty"` + Description nullable.Nullable[string] `json:"description,omitempty"` + Name *string `json:"name,omitempty"` + SecretJwtTemplate nullable.Nullable[map[string]interface{}] `json:"secret_jwt_template,omitempty"` } // UpdateAuthConfigBody defines model for UpdateAuthConfigBody. @@ -2695,6 +2765,25 @@ type UpgradeDatabaseBody struct { // UpgradeDatabaseBodyReleaseChannel defines model for UpgradeDatabaseBody.ReleaseChannel. type UpgradeDatabaseBodyReleaseChannel string +// UpsertContentBody defines model for UpsertContentBody. +type UpsertContentBody struct { + Content *map[string]interface{} `json:"content,omitempty"` + Description *string `json:"description,omitempty"` + FolderId nullable.Nullable[openapi_types.UUID] `json:"folder_id,omitempty"` + Id string `json:"id"` + Name string `json:"name"` + OwnerId float32 `json:"owner_id"` + ProjectId *float32 `json:"project_id,omitempty"` + Type UpsertContentBodyType `json:"type"` + Visibility UpsertContentBodyVisibility `json:"visibility"` +} + +// UpsertContentBodyType defines model for UpsertContentBody.Type. +type UpsertContentBodyType string + +// UpsertContentBodyVisibility defines model for UpsertContentBody.Visibility. +type UpsertContentBodyVisibility string + // V1BackupsResponse defines model for V1BackupsResponse. type V1BackupsResponse struct { Backups []struct { @@ -3218,6 +3307,26 @@ type V1GetServicesHealthParamsServices string // V1BulkDeleteSecretsJSONBody defines parameters for V1BulkDeleteSecrets. type V1BulkDeleteSecretsJSONBody = []string +// V1ProjectListSnippetsParams defines parameters for V1ProjectListSnippets. +type V1ProjectListSnippetsParams struct { + // ProjectRef Project ref + ProjectRef *string `form:"project_ref,omitempty" json:"project_ref,omitempty"` + Type *V1ProjectListSnippetsParamsType `form:"type,omitempty" json:"type,omitempty"` + Cursor *string `form:"cursor,omitempty" json:"cursor,omitempty"` + Limit *string `form:"limit,omitempty" json:"limit,omitempty"` + SortBy *V1ProjectListSnippetsParamsSortBy `form:"sort_by,omitempty" json:"sort_by,omitempty"` + SortOrder *V1ProjectListSnippetsParamsSortOrder `form:"sort_order,omitempty" json:"sort_order,omitempty"` +} + +// V1ProjectListSnippetsParamsType defines parameters for V1ProjectListSnippets. +type V1ProjectListSnippetsParamsType string + +// V1ProjectListSnippetsParamsSortBy defines parameters for V1ProjectListSnippets. +type V1ProjectListSnippetsParamsSortBy string + +// V1ProjectListSnippetsParamsSortOrder defines parameters for V1ProjectListSnippets. +type V1ProjectListSnippetsParamsSortOrder string + // V1GenerateTypescriptTypesParams defines parameters for V1GenerateTypescriptTypes. type V1GenerateTypescriptTypesParams struct { IncludedSchemas *string `form:"included_schemas,omitempty" json:"included_schemas,omitempty"` @@ -3232,12 +3341,16 @@ type V1GetPostgresUpgradeStatusParams struct { type V1ListAllSnippetsParams struct { // ProjectRef Project ref ProjectRef *string `form:"project_ref,omitempty" json:"project_ref,omitempty"` + Type *V1ListAllSnippetsParamsType `form:"type,omitempty" json:"type,omitempty"` Cursor *string `form:"cursor,omitempty" json:"cursor,omitempty"` Limit *string `form:"limit,omitempty" json:"limit,omitempty"` SortBy *V1ListAllSnippetsParamsSortBy `form:"sort_by,omitempty" json:"sort_by,omitempty"` SortOrder *V1ListAllSnippetsParamsSortOrder `form:"sort_order,omitempty" json:"sort_order,omitempty"` } +// V1ListAllSnippetsParamsType defines parameters for V1ListAllSnippets. +type V1ListAllSnippetsParamsType string + // V1ListAllSnippetsParamsSortBy defines parameters for V1ListAllSnippets. type V1ListAllSnippetsParamsSortBy string @@ -3364,6 +3477,12 @@ type V1BulkDeleteSecretsJSONRequestBody = V1BulkDeleteSecretsJSONBody // V1BulkCreateSecretsJSONRequestBody defines body for V1BulkCreateSecrets for application/json ContentType. type V1BulkCreateSecretsJSONRequestBody = CreateSecretBody +// V1ProjectCreateSnippetJSONRequestBody defines body for V1ProjectCreateSnippet for application/json ContentType. +type V1ProjectCreateSnippetJSONRequestBody = CreateContentBody + +// V1ProjectUpdateSnippetJSONRequestBody defines body for V1ProjectUpdateSnippet for application/json ContentType. +type V1ProjectUpdateSnippetJSONRequestBody = UpsertContentBody + // V1UpdateSslEnforcementConfigJSONRequestBody defines body for V1UpdateSslEnforcementConfig for application/json ContentType. type V1UpdateSslEnforcementConfigJSONRequestBody = SslEnforcementRequest