forked from sqlc-dev/sqlc
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Managed databases with any accessible server (sqlc-dev#3421)
Managed databases only work using database servers hosted by sqlc Cloud. I'm going to add support for using managed databases with any database server you can access. Database servers will be configured in a separate servers collection in the configuration file. Each entry will have a mandatory uri field and an optional name. I may add an optional engine field if the URI scheme isn't enough to infer the engine type. When using a database server not hosted by sqlc Cloud, sqlc will automatically create databases as needed based on the schema for the associated query set. All operations against these databases will be read-only, so they can be created once and re-used.
- Loading branch information
1 parent
f498122
commit 757187c
Showing
12 changed files
with
226 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
package dbmanager | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"hash/fnv" | ||
"io" | ||
"net/url" | ||
"strings" | ||
|
||
"github.com/jackc/pgx/v5" | ||
"golang.org/x/sync/singleflight" | ||
|
||
"github.com/sqlc-dev/sqlc/internal/config" | ||
"github.com/sqlc-dev/sqlc/internal/pgx/poolcache" | ||
"github.com/sqlc-dev/sqlc/internal/shfmt" | ||
) | ||
|
||
type CreateDatabaseRequest struct { | ||
Engine string | ||
Migrations []string | ||
} | ||
|
||
type CreateDatabaseResponse struct { | ||
Uri string | ||
} | ||
|
||
type Client interface { | ||
CreateDatabase(context.Context, *CreateDatabaseRequest) (*CreateDatabaseResponse, error) | ||
Close(context.Context) | ||
} | ||
|
||
var flight singleflight.Group | ||
|
||
type ManagedClient struct { | ||
cache *poolcache.Cache | ||
replacer *shfmt.Replacer | ||
servers []config.Server | ||
} | ||
|
||
func dbid(migrations []string) string { | ||
h := fnv.New64() | ||
for _, query := range migrations { | ||
io.WriteString(h, query) | ||
} | ||
return fmt.Sprintf("%x", h.Sum(nil)) | ||
} | ||
|
||
func (m *ManagedClient) CreateDatabase(ctx context.Context, req *CreateDatabaseRequest) (*CreateDatabaseResponse, error) { | ||
hash := dbid(req.Migrations) | ||
name := fmt.Sprintf("sqlc_managed_%s", hash) | ||
|
||
var base string | ||
for _, server := range m.servers { | ||
if server.Engine == config.EnginePostgreSQL { | ||
base = server.URI | ||
break | ||
} | ||
} | ||
|
||
if strings.TrimSpace(base) == "" { | ||
return nil, fmt.Errorf("no PostgreSQL database server found") | ||
} | ||
|
||
serverUri := m.replacer.Replace(base) | ||
pool, err := m.cache.Open(ctx, serverUri) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
uri, err := url.Parse(serverUri) | ||
if err != nil { | ||
return nil, err | ||
} | ||
uri.Path = name | ||
|
||
key := uri.String() | ||
_, err, _ = flight.Do(key, func() (interface{}, error) { | ||
// TODO: Use a parameterized query | ||
row := pool.QueryRow(ctx, | ||
fmt.Sprintf(`SELECT datname FROM pg_database WHERE datname = '%s'`, name)) | ||
|
||
var datname string | ||
if err := row.Scan(&datname); err == nil { | ||
return nil, nil | ||
} | ||
|
||
if _, err := pool.Exec(ctx, fmt.Sprintf(`CREATE DATABASE "%s"`, name)); err != nil { | ||
return nil, err | ||
} | ||
|
||
conn, err := pgx.Connect(ctx, uri.String()) | ||
if err != nil { | ||
return nil, fmt.Errorf("connect %s: %s", name, err) | ||
} | ||
defer conn.Close(ctx) | ||
|
||
var migrationErr error | ||
for _, q := range req.Migrations { | ||
if len(strings.TrimSpace(q)) == 0 { | ||
continue | ||
} | ||
if _, err := conn.Exec(ctx, q); err != nil { | ||
migrationErr = fmt.Errorf("%s: %s", q, err) | ||
break | ||
} | ||
} | ||
|
||
if migrationErr != nil { | ||
pool.Exec(ctx, fmt.Sprintf(`DROP DATABASE "%s" IF EXISTS WITH (FORCE)`, name)) | ||
return nil, migrationErr | ||
} | ||
|
||
return nil, nil | ||
}) | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return &CreateDatabaseResponse{Uri: key}, err | ||
} | ||
|
||
func (m *ManagedClient) Close(ctx context.Context) { | ||
m.cache.Close() | ||
} | ||
|
||
func NewClient(servers []config.Server) *ManagedClient { | ||
return &ManagedClient{ | ||
cache: poolcache.New(), | ||
servers: servers, | ||
replacer: shfmt.NewReplacer(nil), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
SELECT 1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.