Skip to content
This repository has been archived by the owner on Mar 28, 2023. It is now read-only.

Commit

Permalink
[#1545] Migrate existing chat timestamps from seconds to nanoseconds
Browse files Browse the repository at this point in the history
  • Loading branch information
placer14 committed Apr 18, 2019
1 parent 5c76700 commit 5692c53
Show file tree
Hide file tree
Showing 2 changed files with 274 additions and 0 deletions.
117 changes: 117 additions & 0 deletions repo/migrations/Migration023.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package migrations

import (
"database/sql"
"fmt"
"path"
"time"
)

type Migration023_ChatMessage struct {
MessageId string
PeerId string
Subject string
Message string
Read bool
Outgoing bool
Timestamp time.Time
}

type Migration023 struct{}

func (Migration023) Up(repoPath, databasePassword string, testnetEnabled bool) error {
var databaseFilePath string
if testnetEnabled {
databaseFilePath = path.Join(repoPath, "datastore", "testnet.db")
} else {
databaseFilePath = path.Join(repoPath, "datastore", "mainnet.db")
}

db, err := sql.Open("sqlite3", databaseFilePath)
if err != nil {
return err
}
if databasePassword != "" {
p := fmt.Sprintf("pragma key = '%s';", databasePassword)
_, err := db.Exec(p)
if err != nil {
return err
}
}

if err := migrateTimestamp(db, func(in int64) int64 {
// convert from seconds to nanoseconds
return time.Unix(in, 0).UnixNano()
}); err != nil {
return err
}

if err := writeRepoVer(repoPath, 23); err != nil {
return fmt.Errorf("bumping repover to 18: %s", err.Error())
}
return nil
}

func (Migration023) Down(repoPath, databasePassword string, testnetEnabled bool) error {
var databaseFilePath string
if testnetEnabled {
databaseFilePath = path.Join(repoPath, "datastore", "testnet.db")
} else {
databaseFilePath = path.Join(repoPath, "datastore", "mainnet.db")
}

db, err := sql.Open("sqlite3", databaseFilePath)
if err != nil {
return err
}
if databasePassword != "" {
p := fmt.Sprintf("pragma key = '%s';", databasePassword)
_, err := db.Exec(p)
if err != nil {
return err
}
}

if err := migrateTimestamp(db, func(in int64) int64 {
// convert from seconds to nanoseconds
return time.Unix(0, in).Unix()
}); err != nil {
return err
}

if err := writeRepoVer(repoPath, 22); err != nil {
return fmt.Errorf("dropping repover to 22: %s", err.Error())
}
return nil
}

func migrateTimestamp(db *sql.DB, migrate func(int64) int64) error {
const (
selectChatSQL = "select messageID, timestamp from chat;"
updateChatSQL = "update chat set timestamp=? where messageID=?;"
)

chatRows, err := db.Query(selectChatSQL)
if err != nil {
return fmt.Errorf("query chat: %s", err.Error())
}

var updates = make(map[string]int64)
for chatRows.Next() {
var (
messageID string
timestamp int64
)
if err := chatRows.Scan(&messageID, &timestamp); err != nil {
return fmt.Errorf("unexpected error scanning message (%s): %s", messageID, err.Error())
}
updates[messageID] = migrate(timestamp)
}
chatRows.Close()
for id, newTime := range updates {
if _, err := db.Exec(updateChatSQL, newTime, id); err != nil {
return fmt.Errorf("updating record (%s): %s", id, err.Error())
}
}
return nil
}
157 changes: 157 additions & 0 deletions repo/migrations/Migration023_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package migrations_test

import (
"database/sql"
"fmt"
"io/ioutil"
"os"
"strings"
"testing"
"time"

"github.com/OpenBazaar/openbazaar-go/repo/migrations"
"github.com/OpenBazaar/openbazaar-go/schema"
)

func TestMigration023(t *testing.T) {
var (
basePath = schema.GenerateTempPath()
testRepoPath, err = schema.OpenbazaarPathTransform(basePath, true)
)
if err != nil {
t.Fatal(err)
}
appSchema, err := schema.NewCustomSchemaManager(schema.SchemaContext{DataPath: testRepoPath, TestModeEnabled: true})
if err != nil {
t.Fatal(err)
}
if err = appSchema.BuildSchemaDirectories(); err != nil {
t.Fatal(err)
}
defer appSchema.DestroySchemaDirectories()

var (
databasePath = appSchema.DatabasePath()
schemaPath = appSchema.DataPathJoin("repover")

//schemaSQL = "pragma key = 'foobarbaz';"
CreateTableChatSQL = "create table chat (messageID text primary key not null, peerID text, subject text, message text, read integer, timestamp integer, outgoing integer);"
insertChatSQL = "insert into chat(messageID, peerID, subject, message, read, timestamp, outgoing) values(?,?,?,?,?,?,?);"
selectChatSQL = "select messageID, timestamp from chat;"
setupSQL = strings.Join([]string{
//schemaSQL,
CreateTableChatSQL,
}, " ")
)
fmt.Println("test path:", databasePath)
db, err := sql.Open("sqlite3", databasePath)
if err != nil {
t.Fatal(err)
}
if _, err = db.Exec(setupSQL); err != nil {
t.Fatal(err)
}

// create chat records
var examples = []migrations.Migration023_ChatMessage{
{
MessageId: "message1",
PeerId: "peerid",
Timestamp: time.Date(2210, 1, 2, 3, 4, 5, 0, time.UTC),
},
{
MessageId: "message2",
PeerId: "peerid",
Timestamp: time.Date(2018, 1, 2, 3, 4, 5, 0, time.UTC),
},
{
MessageId: "message3",
PeerId: "peerid",
Timestamp: time.Date(2010, 1, 2, 3, 4, 5, 0, time.UTC),
},
}
for _, e := range examples {
_, err = db.Exec(insertChatSQL,
e.MessageId,
e.PeerId,
e.Subject,
e.Message,
false,
e.Timestamp.Unix(),
false,
)
if err != nil {
t.Fatal(err)
}
}

// create schema version file
if err = ioutil.WriteFile(schemaPath, []byte("22"), os.ModePerm); err != nil {
t.Fatal(err)
}

// execute migration up
m := migrations.Migration023{}
if err := m.Up(testRepoPath, "", true); err != nil {
t.Fatal(err)
}

// assert repo version updated
if err = appSchema.VerifySchemaVersion("23"); err != nil {
t.Fatal(err)
}

// verify change was applied properly
chatRows, err := db.Query(selectChatSQL)
if err != nil {
t.Fatal(err)
}

for chatRows.Next() {
var (
messageID string
timestampInt int64
)
if err := chatRows.Scan(&messageID, &timestampInt); err != nil {
t.Fatal(err)
}
for _, e := range examples {
if messageID == e.MessageId && timestampInt != e.Timestamp.UnixNano() {
t.Errorf("expected message (%s) to have nanosecond-based timestamp, but was not", e.MessageId)
}
}
}
chatRows.Close()

// execute migration down
if err := m.Down(testRepoPath, "", true); err != nil {
t.Fatal(err)
}

// assert repo version reverted
if err = appSchema.VerifySchemaVersion("22"); err != nil {
t.Fatal(err)
}

// verify change was reverted properly
chatRows, err = db.Query(selectChatSQL)
if err != nil {
t.Fatal(err)
}

for chatRows.Next() {
var (
messageID string
timestampInt int64
)
if err := chatRows.Scan(&messageID, &timestampInt); err != nil {
t.Fatal(err)
}
for _, e := range examples {
if messageID == e.MessageId && timestampInt != e.Timestamp.Unix() {
t.Errorf("expected message (%s) to have second-based timestamp, but did not", e.MessageId)
}
}
}
chatRows.Close()
}

0 comments on commit 5692c53

Please sign in to comment.