-
Notifications
You must be signed in to change notification settings - Fork 526
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow init goose version table before querying it. #461
Comments
I could be wrong, but it feels like this should be addressed in goose for everyone. I think there is a more robust way to ask the question "do we need to create the version table?". In the current implementation, we query a table that may or may not exist, discard the error wholesale, and then attempt to create the table on any error. Ideally, we could modify this query to check whether the table exists by utilizing the upper/db does this for various databases to resolve collections to tables, and it works quite nicely (from my experience). Example: This seems like a safer and more explicit approach, maybe @VojtechVitek has some thoughts here? |
I initially thought it might be better not to add this check to goose to avoid the additional query to the DB if some users don't care about the error and prefer fewer roundtrips. If you think this query should be part of goose then I don't mind adding it. From a quick search looks like most of the currently supported drivers also have
|
Correct, this would be implemented for each database based on what it supports. If we have a database-native way of asking "does this table exist" then we leverage it, otherwise, we continue doing what we do today (for that specific database). I'm a bit hesitant to expose create table operation to users, because if goose loses control of owning that table it'll make it difficult to evolve goose, e.g., #288. I am still unsure how to do this in a backward-compatible way, but that's outside the scope of this discussion. I think a reasonable approach might be to extend the |
@mfridman I added another PR with the desired change. The old PR can be closed. |
Sorry for the delay, I'll try to get to this issue (and #463) whenever I can. A bit swamped with work at the moment. |
Figured I'd drop by with an idea. The new However, for more advanced use cases you could extend the default func (p *Provider) ensureVersionTable(ctx context.Context, conn *sql.Conn) (retErr error) {
// existor is an interface that extends the Store interface with a method to check if the
// version table exists. This API is not stable and may change in the future.
type existor interface {
TableExists(context.Context, database.DBTxConn, string) (bool, error)
}
if e, ok := p.store.(existor); ok {
exists, err := e.TableExists(ctx, conn, p.store.Tablename())
if err != nil {
return fmt.Errorf("failed to check if version table exists: %w", err)
}
if exists {
return nil
}
} else { All you have to do is embed a Store and then add your own Added an example of how this might work in fad964c tl;dr - here's how it'd work for sqlite3, but could be extended to practically any database. type customStoreSQLite3 struct {
database.Store
}
func (s *customStoreSQLite3) TableExists(ctx context.Context, db database.DBTxConn, name string) (bool, error) {
q := `SELECT EXISTS (SELECT 1 FROM sqlite_master WHERE type='table' AND name=$1) AS table_exists`
var exists bool
if err := db.QueryRowContext(ctx, q, name).Scan(&exists); err != nil {
return false, err
}
return exists, nil
} |
Added a mechanism to achieve this in #860, using postgres as an example It should now be possible to do this both for existing dialects and custom ones in a standardized way. |
Ended up merging #860, which means we could take a lot of the logic from #463 and apply it to the rest of the databases, all it'd take is to implement a E.g., here's the postges implementation func (p *Postgres) TableExists(tableName string) string {
schemaName, tableName := parseTableIdentifier(tableName)
q := `SELECT EXISTS ( SELECT FROM pg_tables WHERE schemaname = '%s' AND tablename = '%s' )`
return fmt.Sprintf(q, schemaName, tableName)
} |
When running goose for the first time on a clean DB the following lines are printed to the DB log (using Postgres):
The reason is that
EnsureDBVersion
is always trying first to querygoose_db_version
and only if it fails it creates the version table.While this logic makes sense, we are concerned that our customers running our service will see this error in their database and think this is a bug.
In our service, we have a logic before running any migration that checks if the DB is "clean"/has our tables/has tables we don't know (used to prevent installing our service to a dirty/used database).
I wonder if it is possible to make
createVersionTable
public so we can call it when we identify the DB is clean and, by doing so, avoid the error in the DB log.If you are open to this change, I'll be happy to open a PR adding this.
The text was updated successfully, but these errors were encountered: