67
vendor/github.com/status-im/status-go/protocol/sqlite/ad_hoc_migration.go
generated
vendored
Normal file
67
vendor/github.com/status-im/status-go/protocol/sqlite/ad_hoc_migration.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
_ "github.com/mutecomm/go-sqlcipher/v4" // We require go sqlcipher that overrides default implementation
|
||||
"github.com/pkg/errors"
|
||||
"github.com/status-im/migrate/v4"
|
||||
)
|
||||
|
||||
const communitiesMigrationVersion uint = 1605075346
|
||||
|
||||
// FixCommunitiesMigration fixes an issue with a released migration
|
||||
// In some instances if it was interrupted the migration would be skipped
|
||||
// but marked as completed.
|
||||
// What we do here is that we check whether we are at that migration, if
|
||||
// so we check that the communities table is present, if not we re-run that
|
||||
// migration.
|
||||
func FixCommunitiesMigration(version uint, dirty bool, m *migrate.Migrate, db *sql.DB) error {
|
||||
// If the version is not the same, ignore
|
||||
if version != communitiesMigrationVersion {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If it's dirty, it will be replayed anyway
|
||||
if dirty {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Otherwise we check whether it actually succeeded by checking for the
|
||||
// presence of the communities_communities table
|
||||
|
||||
var name string
|
||||
|
||||
err := db.QueryRow(`SELECT name FROM sqlite_master WHERE type='table' AND name='communities_communities'`).Scan(&name)
|
||||
|
||||
// If the err is nil, it means the migration went through fine
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If any other other, we return the error as that's unexpected
|
||||
if err != sql.ErrNoRows {
|
||||
return errors.Wrap(err, "failed to find the communities table")
|
||||
}
|
||||
|
||||
// We replay the migration then
|
||||
return ReplayLastMigration(version, m)
|
||||
}
|
||||
|
||||
func ReplayLastMigration(version uint, m *migrate.Migrate) error {
|
||||
// Force version if dirty so it's not dirty anymore
|
||||
if err := m.Force(int(version)); err != nil {
|
||||
return errors.Wrap(err, "failed to force migration")
|
||||
}
|
||||
|
||||
// Step down 1 and we retry
|
||||
if err := m.Steps(-1); err != nil {
|
||||
return errors.Wrap(err, "failed to step down")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ApplyAdHocMigrations(version uint, dirty bool, m *migrate.Migrate, db *sql.DB) error {
|
||||
return FixCommunitiesMigration(version, dirty, m, db)
|
||||
}
|
||||
88
vendor/github.com/status-im/status-go/protocol/sqlite/db.go
generated
vendored
Normal file
88
vendor/github.com/status-im/status-go/protocol/sqlite/db.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
_ "github.com/mutecomm/go-sqlcipher/v4" // We require go sqlcipher that overrides default implementation
|
||||
"github.com/status-im/migrate/v4"
|
||||
"github.com/status-im/migrate/v4/database/sqlcipher"
|
||||
bindata "github.com/status-im/migrate/v4/source/go_bindata"
|
||||
mvdsmigrations "github.com/status-im/mvds/persistenceutil"
|
||||
)
|
||||
|
||||
var migrationsTable = "status_protocol_go_" + sqlcipher.DefaultMigrationsTable
|
||||
|
||||
// applyMigrations allows to apply bindata migrations on the current *sql.DB.
|
||||
// `assetNames` is a list of assets with migrations and `assetGetter` is responsible
|
||||
// for returning the content of the asset with a given name.
|
||||
func applyMigrations(db *sql.DB, assetNames []string, assetGetter func(name string) ([]byte, error)) error {
|
||||
resources := bindata.Resource(
|
||||
assetNames,
|
||||
assetGetter,
|
||||
)
|
||||
|
||||
source, err := bindata.WithInstance(resources)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create migration source")
|
||||
}
|
||||
|
||||
driver, err := sqlcipher.WithInstance(db, &sqlcipher.Config{
|
||||
MigrationsTable: migrationsTable,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create driver")
|
||||
}
|
||||
|
||||
m, err := migrate.NewWithInstance(
|
||||
"go-bindata",
|
||||
source,
|
||||
"sqlcipher",
|
||||
driver,
|
||||
)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create migration instance")
|
||||
}
|
||||
|
||||
version, dirty, err := m.Version()
|
||||
if err != nil && err != migrate.ErrNilVersion {
|
||||
return errors.Wrap(err, "could not get version")
|
||||
}
|
||||
|
||||
err = ApplyAdHocMigrations(version, dirty, m, db)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to apply ad-hoc migrations")
|
||||
}
|
||||
|
||||
if dirty {
|
||||
err = ReplayLastMigration(version, m)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to replay last migration")
|
||||
}
|
||||
}
|
||||
|
||||
if err = m.Up(); err != migrate.ErrNoChange {
|
||||
return errors.Wrap(err, "failed to migrate")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Migrate(database *sql.DB) error {
|
||||
// Apply migrations for all components.
|
||||
err := mvdsmigrations.Migrate(database)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to apply mvds migrations")
|
||||
}
|
||||
|
||||
migrationNames, migrationGetter, err := prepareMigrations(defaultMigrations)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to prepare status-go/protocol migrations")
|
||||
}
|
||||
err = applyMigrations(database, migrationNames, migrationGetter)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to apply status-go/protocol migrations")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
7
vendor/github.com/status-im/status-go/protocol/sqlite/doc.go
generated
vendored
Normal file
7
vendor/github.com/status-im/status-go/protocol/sqlite/doc.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// Package sqlite is responsible for creation of encrypted sqlite3 database using sqlcipher driver.
|
||||
// It is optimized for mobile usage as well.
|
||||
//
|
||||
// sqlite package also provides a capability to apply bindata migration.
|
||||
// You can keep your migrations close to your business logic and use this package
|
||||
// to create an encrypted sqlite3 database and then apply the migrations easily.
|
||||
package sqlite
|
||||
75
vendor/github.com/status-im/status-go/protocol/sqlite/migrations.go
generated
vendored
Normal file
75
vendor/github.com/status-im/status-go/protocol/sqlite/migrations.go
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
encryptmigrations "github.com/status-im/status-go/protocol/encryption/migrations"
|
||||
appmigrations "github.com/status-im/status-go/protocol/migrations"
|
||||
push_notification_client_migrations "github.com/status-im/status-go/protocol/pushnotificationclient/migrations"
|
||||
push_notification_server_migrations "github.com/status-im/status-go/protocol/pushnotificationserver/migrations"
|
||||
wakumigrations "github.com/status-im/status-go/protocol/transport/migrations"
|
||||
)
|
||||
|
||||
type getter func(string) ([]byte, error)
|
||||
|
||||
type migrationsWithGetter struct {
|
||||
Names []string
|
||||
Getter getter
|
||||
}
|
||||
|
||||
var defaultMigrations = []migrationsWithGetter{
|
||||
{
|
||||
Names: wakumigrations.AssetNames(),
|
||||
Getter: wakumigrations.Asset,
|
||||
},
|
||||
{
|
||||
Names: encryptmigrations.AssetNames(),
|
||||
Getter: encryptmigrations.Asset,
|
||||
},
|
||||
{
|
||||
Names: appmigrations.AssetNames(),
|
||||
Getter: appmigrations.Asset,
|
||||
},
|
||||
{
|
||||
Names: push_notification_server_migrations.AssetNames(),
|
||||
Getter: push_notification_server_migrations.Asset,
|
||||
},
|
||||
{
|
||||
Names: push_notification_client_migrations.AssetNames(),
|
||||
Getter: push_notification_client_migrations.Asset,
|
||||
},
|
||||
}
|
||||
|
||||
func prepareMigrations(migrations []migrationsWithGetter) ([]string, getter, error) {
|
||||
var allNames []string
|
||||
nameToGetter := make(map[string]getter)
|
||||
|
||||
for _, m := range migrations {
|
||||
for _, name := range m.Names {
|
||||
if !validateName(name) {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := nameToGetter[name]; ok {
|
||||
return nil, nil, errors.Errorf("migration with name %s already exists", name)
|
||||
}
|
||||
allNames = append(allNames, name)
|
||||
nameToGetter[name] = m.Getter
|
||||
}
|
||||
}
|
||||
|
||||
return allNames, func(name string) ([]byte, error) {
|
||||
getter, ok := nameToGetter[name]
|
||||
if !ok {
|
||||
return nil, errors.Errorf("no migration for name %s", name)
|
||||
}
|
||||
return getter(name)
|
||||
}, nil
|
||||
}
|
||||
|
||||
// validateName verifies that only *.sql files are taken into consideration.
|
||||
func validateName(name string) bool {
|
||||
return strings.HasSuffix(name, ".sql")
|
||||
}
|
||||
Reference in New Issue
Block a user