diff --git a/cmd/gen.go b/cmd/gen.go index c81339d59..6d4028a48 100644 --- a/cmd/gen.go +++ b/cmd/gen.go @@ -55,10 +55,18 @@ var ( Allowed: []string{ types.LangTypescript, types.LangGo, + types.LangSwift, }, Value: types.LangTypescript, } - postgrestV9Compat bool + postgrestV9Compat bool + swiftAccessControl = utils.EnumFlag{ + Allowed: []string{ + types.SwiftInternalAccessControl, + types.SwiftPublicAccessControl, + }, + Value: types.SwiftInternalAccessControl, + } genTypesCmd = &cobra.Command{ Use: "types", @@ -79,7 +87,7 @@ var ( return err } } - return types.Run(ctx, flags.ProjectRef, flags.DbConfig, lang.Value, schema, postgrestV9Compat, afero.NewOsFs()) + return types.Run(ctx, flags.ProjectRef, flags.DbConfig, lang.Value, schema, postgrestV9Compat, swiftAccessControl.Value, afero.NewOsFs()) }, Example: ` supabase gen types --local supabase gen types --linked --lang=go @@ -108,6 +116,7 @@ func init() { genTypesCmd.MarkFlagsMutuallyExclusive("local", "linked", "project-id", "db-url") genFlags.Var(&lang, "lang", "Output language of the generated types.") genFlags.StringSliceVarP(&schema, "schema", "s", []string{}, "Comma separated list of schema to include.") + genFlags.Var(&swiftAccessControl, "swift-access-control", "Access control for Swift generated types.") genFlags.BoolVar(&postgrestV9Compat, "postgrest-v9-compat", false, "Generate types compatible with PostgREST v9 and below. Only use together with --db-url.") genTypesCmd.AddCommand(genTypesTypescriptCmd) genCmd.AddCommand(genTypesCmd) diff --git a/internal/gen/types/types.go b/internal/gen/types/types.go index eae3ee327..9ffc7dc72 100644 --- a/internal/gen/types/types.go +++ b/internal/gen/types/types.go @@ -19,9 +19,15 @@ import ( const ( LangTypescript = "typescript" LangGo = "go" + LangSwift = "swift" ) -func Run(ctx context.Context, projectId string, dbConfig pgconn.Config, lang string, schemas []string, postgrestV9Compat bool, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error { +const ( + SwiftPublicAccessControl = "public" + SwiftInternalAccessControl = "internal" +) + +func Run(ctx context.Context, projectId string, dbConfig pgconn.Config, lang string, schemas []string, postgrestV9Compat bool, swiftAccessControl string, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error { originalURL := utils.ToPostgresURL(dbConfig) // Add default schemas if --schema flag is not specified if len(schemas) == 0 { @@ -86,6 +92,7 @@ func Run(ctx context.Context, projectId string, dbConfig pgconn.Config, lang str "PG_META_DB_URL=" + escaped, "PG_META_GENERATE_TYPES=" + lang, "PG_META_GENERATE_TYPES_INCLUDED_SCHEMAS=" + included, + "PG_META_GENERATE_TYPES_SWIFT_ACCESS_CONTROL=" + swiftAccessControl, fmt.Sprintf("PG_META_GENERATE_TYPES_DETECT_ONE_TO_ONE_RELATIONSHIPS=%v", !postgrestV9Compat), }, Cmd: []string{"node", "dist/server/server.js"}, diff --git a/internal/gen/types/types_test.go b/internal/gen/types/types_test.go index 666e291cb..21b14eb68 100644 --- a/internal/gen/types/types_test.go +++ b/internal/gen/types/types_test.go @@ -48,7 +48,7 @@ func TestGenLocalCommand(t *testing.T) { conn := pgtest.NewConn() defer conn.Close(t) // Run test - assert.NoError(t, Run(context.Background(), "", dbConfig, LangTypescript, []string{}, true, fsys, conn.Intercept)) + assert.NoError(t, Run(context.Background(), "", dbConfig, LangTypescript, []string{}, true, "", fsys, conn.Intercept)) // Validate api assert.Empty(t, apitest.ListUnmatchedRequests()) }) @@ -63,7 +63,7 @@ func TestGenLocalCommand(t *testing.T) { Get("/v" + utils.Docker.ClientVersion() + "/containers/" + utils.DbId). Reply(http.StatusServiceUnavailable) // Run test - assert.Error(t, Run(context.Background(), "", dbConfig, LangTypescript, []string{}, true, fsys)) + assert.Error(t, Run(context.Background(), "", dbConfig, LangTypescript, []string{}, true, "", fsys)) // Validate api assert.Empty(t, apitest.ListUnmatchedRequests()) }) @@ -83,7 +83,30 @@ func TestGenLocalCommand(t *testing.T) { Get("/v" + utils.Docker.ClientVersion() + "/images"). Reply(http.StatusServiceUnavailable) // Run test - assert.Error(t, Run(context.Background(), "", dbConfig, LangTypescript, []string{}, true, fsys)) + assert.Error(t, Run(context.Background(), "", dbConfig, LangTypescript, []string{}, true, "", fsys)) + // Validate api + assert.Empty(t, apitest.ListUnmatchedRequests()) + }) + + t.Run("generates swift types", func(t *testing.T) { + const containerId = "test-pgmeta" + imageUrl := utils.GetRegistryImageUrl(utils.PgmetaImage) + // Setup in-memory fs + fsys := afero.NewMemMapFs() + // Setup mock docker + require.NoError(t, apitest.MockDocker(utils.Docker)) + defer gock.OffAll() + gock.New(utils.Docker.DaemonHost()). + Get("/v" + utils.Docker.ClientVersion() + "/containers/" + utils.DbId). + Reply(http.StatusOK). + JSON(types.ContainerJSON{}) + apitest.MockDockerStart(utils.Docker, imageUrl, containerId) + require.NoError(t, apitest.MockDockerLogs(utils.Docker, containerId, "hello world")) + // Setup mock postgres + conn := pgtest.NewConn() + defer conn.Close(t) + // Run test + assert.NoError(t, Run(context.Background(), "", dbConfig, LangSwift, []string{}, true, SwiftInternalAccessControl, fsys, conn.Intercept)) // Validate api assert.Empty(t, apitest.ListUnmatchedRequests()) }) @@ -106,7 +129,7 @@ func TestGenLinkedCommand(t *testing.T) { Reply(200). JSON(api.TypescriptResponse{Types: ""}) // Run test - assert.NoError(t, Run(context.Background(), projectId, pgconn.Config{}, LangTypescript, []string{}, true, fsys)) + assert.NoError(t, Run(context.Background(), projectId, pgconn.Config{}, LangTypescript, []string{}, true, "", fsys)) // Validate api assert.Empty(t, apitest.ListUnmatchedRequests()) }) @@ -121,7 +144,7 @@ func TestGenLinkedCommand(t *testing.T) { Get("/v1/projects/" + projectId + "/types/typescript"). ReplyError(errNetwork) // Run test - err := Run(context.Background(), projectId, pgconn.Config{}, LangTypescript, []string{}, true, fsys) + err := Run(context.Background(), projectId, pgconn.Config{}, LangTypescript, []string{}, true, "", fsys) // Validate api assert.ErrorIs(t, err, errNetwork) assert.Empty(t, apitest.ListUnmatchedRequests()) @@ -136,7 +159,7 @@ func TestGenLinkedCommand(t *testing.T) { Get("/v1/projects/" + projectId + "/types/typescript"). Reply(http.StatusServiceUnavailable) // Run test - assert.Error(t, Run(context.Background(), projectId, pgconn.Config{}, LangTypescript, []string{}, true, fsys)) + assert.Error(t, Run(context.Background(), projectId, pgconn.Config{}, LangTypescript, []string{}, true, "", fsys)) }) } @@ -161,7 +184,7 @@ func TestGenRemoteCommand(t *testing.T) { conn := pgtest.NewConn() defer conn.Close(t) // Run test - assert.NoError(t, Run(context.Background(), "", dbConfig, LangTypescript, []string{"public"}, true, afero.NewMemMapFs(), conn.Intercept)) + assert.NoError(t, Run(context.Background(), "", dbConfig, LangTypescript, []string{"public"}, true, "", afero.NewMemMapFs(), conn.Intercept)) // Validate api assert.Empty(t, apitest.ListUnmatchedRequests()) })